diff --git a/assets/InstructionEditor/.gitignore b/assets/InstructionEditor/.gitignore new file mode 100644 index 0000000..8d5d458 --- /dev/null +++ b/assets/InstructionEditor/.gitignore @@ -0,0 +1,57 @@ +# 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 +# + +# Delphi compiler-generated binaries (safe to delete) +*.exe +*.dll +*.bpl +*.bpi +*.dcp +*.so +*.apk +*.drc +*.map +*.dres +*.rsm +*.tds +*.dcu +*.lib + +# Delphi autogenerated files (duplicated info) +*.cfg +*Resource.rc + +# Delphi local files (user-specific info) +*.local +*.identcache +*.projdata +*.tvsconfig +*.dsk + +# Delphi history and backups +__history/ +*.~* + +# Castalia statistics file +*.stat diff --git a/assets/InstructionEditor/Forms/Editors/formEditorCPUIDFeatureFlags.dfm b/assets/InstructionEditor/Forms/Editors/formEditorCPUIDFeatureFlags.dfm new file mode 100644 index 0000000..0e79900 --- /dev/null +++ b/assets/InstructionEditor/Forms/Editors/formEditorCPUIDFeatureFlags.dfm @@ -0,0 +1,318 @@ +object frmEditorCPUIDFeatureFlags: TfrmEditorCPUIDFeatureFlags + Left = 0 + Top = 0 + BorderStyle = bsDialog + Caption = 'frmEditorCPUIDFeatureFlags' + ClientHeight = 321 + ClientWidth = 494 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object GroupBox: TGroupBox + AlignWithMargins = True + Left = 3 + Top = 279 + Width = 488 + Height = 39 + Margins.Top = 0 + Align = alBottom + TabOrder = 1 + DesignSize = ( + 488 + 39) + object btnCancel: TButton + Left = 368 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Cancel' + ImageIndex = 1 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 1 + OnClick = btnCancelClick + end + object btnApply: TButton + Left = 250 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Apply' + ImageIndex = 0 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 0 + OnClick = btnApplyClick + end + end + object VirtualTreeView: TVirtualStringTree + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 488 + Height = 273 + Align = alClient + Header.AutoSizeIndex = -1 + Header.Font.Charset = DEFAULT_CHARSET + Header.Font.Color = clWindowText + Header.Font.Height = -11 + Header.Font.Name = 'Tahoma' + Header.Font.Style = [] + Header.MainColumn = -1 + Images = imgTreeView + TabOrder = 0 + TreeOptions.MiscOptions = [toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toAlwaysHideSelection, toUseBlendedSelection] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnChecked = VirtualTreeViewChecked + OnCollapsing = VirtualTreeViewCollapsing + OnFreeNode = VirtualTreeViewFreeNode + OnGetText = VirtualTreeViewGetText + OnGetImageIndex = VirtualTreeViewGetImageIndex + Columns = <> + end + object imgIcons16: TcxImageList + FormatVersion = 1 + DesignInfo = 2097208 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 20000000000000040000000000000000000000000000000000000000001B0000 + 0033000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000001B00000000004B29A00089 + 49FF008747FF008747FF008747FF008747FF008747FF008747FF008747FF0087 + 47FF008747FF008747FF008747FF008949FF004B29A000000000008949FF07E4 + A4FF07E5A5FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4 + A4FF07E4A4FF07E4A4FF07E5A5FF07E4A4FF008949FF00000000008747FF13E7 + AAFF00DB9BFF00DA9AFF00DA99FF00DA99FF00DA99FF00DA99FF00DA9AFF00DA + 9AFF00DA9AFF00DA9AFF00DB9BFF13E7AAFF008747FF00000000008746FF1EE7 + AEFF00D699FF00D698FF00D495FF00D391FF00D391FF00D495FF00D698FF00D6 + 99FF00D699FF00D699FF00D699FF1EE7AEFF008746FF00000000008746FF2AE9 + B3FF00D299FF00D095FF00CC8DFFFFFFFFFFFFFFFFFF00CC8DFF00D096FF00D2 + 99FF00D29AFF00D29AFF00D29AFF2AE9B3FF008746FF00000000008746FF35EA + B7FF00CD96FF00C98DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C98DFF00CD + 96FF00CF99FF00CF9AFF00CF9AFF36EAB8FF008746FF00000000008745FF3EEB + BBFF00C692FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C4 + 8DFF00C995FF00CA99FF00CA99FF41ECBDFF008745FF00000000008745FF4BED + BFFF00C393FFFFFFFFFFFFFFFFFF00C08BFF00BF8BFFFFFFFFFFFFFFFFFFFFFF + FFFF00C18EFF00C596FF00C699FF4DEDC0FF008745FF00000000008744FF58EF + C5FF00C197FF00BF93FF00C093FF00C196FF00C196FF00BC8EFFFFFFFFFFFFFF + FFFFFFFFFFFF00BC8EFF00C096FF58EFC5FF008744FF00000000008744FF64F1 + CAFF00BE99FF00C099FF00C09AFF00C19BFF00C19AFF00BE97FF00B98EFFFFFF + FFFFFFFFFFFFFFFFFFFF00BA92FF62F0C9FF008744FF00000000008744FF71F2 + CFFF00BB99FF00BD9AFF00BE9BFF00BE9BFF00BE9BFF00BE9AFF00BB96FF00B6 + 8EFFFFFFFFFFFFFFFFFF00B792FF6EF2CDFF008744FF00000000008744FF7BF4 + D3FF00B699FF00B89AFF00B99BFF00B99BFF00B99BFF00B99BFF00B89AFF00B7 + 98FF00B494FF00B493FF00B496FF7AF3D3FF008744FF00000000008744FF86F5 + D8FF00B198FF00B299FF00B399FF00B399FF00B399FF00B399FF00B399FF00B2 + 99FF00B298FF00B297FF00B197FF86F5D8FF008744FF00000000008946FF8AF2 + D9FF92F6DEFF93F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6 + DDFF94F6DDFF93F6DDFF92F6DEFF8AF2D9FF008946FF00000000004B29880089 + 46FF008743FF008643FF008643FF008643FF008643FF008643FF008643FF0086 + 43FF008643FF008643FF008743FF008946FF004B298800000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0013000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000003300000013000000001117 + 487E2D3CC0FF2B3BBEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3A + BEFF2A3ABEFF2A3ABEFF2A3ABEFF2B3BBEFF2D3CC0FF1117487E000000002D3D + C0FF6172FAFF6A7DFFFF697CFFFF6D80FFFF7485FFFF7788FFFF7788FFFF7788 + FFFF7485FFFF6D7FFFFF697CFFFF6A7DFFFF6172FAFF2D3DC0FF000000002B3B + BEFF6578FFFF5F73FEFF6F80FFFF7989FFFF5868E6FF3E4ED0FF3F4FD1FF3E4E + D0FF5767E5FF7887FEFF6E7FFFFF5F73FEFF6578FFFF2B3BBEFF000000002B3B + BEFF5D72FFFF697BFEFF7785F8FF3949CAFF1E2A89B70B0F303F07091D26070A + 1F552636B9FF5A6FFDFF576CFAFF687AFCFF5D71FFFF2B3BBEFF000000002C3B + BFFF586EFEFF8593FFFF3B4BCAFF0E143F530000000000000000000000332B3A + BDFF5970FEFF546AFBFF7F8FFFFF8290FDFF586EFEFF2C3BBFFF000000002C3C + BFFF536BFCFF707CE7FF1E2A89BB0000000000000000000000332C3BBEFF546B + FBFF5067F8FF8796FFFF3B4BCDFF6D79E5FF536AFCFF2C3CBFFF000000002D3D + BFFF4F68FBFF4E5BD1FF0B0F304500000000000000332C3BBEFF4E66F9FF4A63 + F6FF8C99FFFF2737BCFF07091F314D5AD0FF4F68FBFF2D3DBFFF000000002E3D + C0FF4A64F9FF3446CDFF07091D2D000000332D3CBEFF4862F7FF445DF4FF8E9C + FFFF2838BDFF0000000007091D313446CDFF4A64F9FF2E3DC0FF000000002E3D + C0FF4660F7FF3445CCFF080A20552D3CBEFF445DF4FF3F59F1FF929FFFFF2838 + BDFF00000000000000000C0F305B3445CDFF4660F7FF2E3DC0FF000000002E3E + C0FF405BF3FF384DDBFF2E3CBCFF3E59F2FF3954EFFF95A2FFFF2838BDFF0000 + 00000000000000000011222D8AC5384EDCFF405BF3FF2E3EC0FF000000002F3E + C0FF3955F0FF3951EAFF3954EEFF3651EDFF9AA5FFFF2838BDFF000000080000 + 000D0000002510153F753041C8FF3A53EBFF3A55F0FF2F3EC0FF000000002E3D + BFFF3A54EFFF324DE9FF334DE9FF324DEBFF2A39BCFF070A1F5507091D510B0F + 3065212D8AC52F41C8FF314CE4FF324DEBFF3A54EFFF2E3DBFFF000000002B3B + BFFF6A7DFDFF334EE8FF2643E4FF2642E3FF253CD4FF2739C7FF273AC8FF273A + C8FF263DD5FF2743E5FF2643E6FF334EE9FF6A7DFDFF2B3BBFFF000000002B3B + C0FF929DFCFFAAB3FFFFAAB3FFFFAAB3FFFFAAB4FFFFAAB4FFFFAAB4FFFFAAB4 + FFFFAAB4FFFFAAB3FFFFAAB3FFFFAAB3FFFF929DFCFF2B3BC0FF000000001117 + 485E2A3AC0FF2838BFFF2737BEFF2737BEFF2737BEFF2737BFFF2737BFFF2737 + BFFF2737BEFF2737BEFF2737BEFF2838BFFF2A3AC0FF1117485E} + end> + end + object imgTreeView: TcxImageList + FormatVersion = 1 + DesignInfo = 2097288 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000300000 + 0033000000330000003300000033000000330000003300000033000000330000 + 00330000003300000033000000330000002F00000000000000004190C6F24398 + D2FF4094D0FF3E92CFFF3E92CEFF3F92CEFF3F92CEFF3F92CEFF3F92CEFF3F92 + CEFF3F92CEFF3F92CEFF3F93CFFF3D8BC2F00000000E000000004499D2FF3F94 + D0FFABFBFFFF9BF3FFFF92F1FFFF93F1FFFF93F1FFFF93F1FFFF93F1FFFF93F1 + FFFF93F1FFFF93F1FFFFA6F8FFFF65B8E3FF122A3A5F000000004398D2FF4FA6 + D9FF8EDAF5FFA2EEFFFF82E5FEFF84E5FEFF84E5FEFF85E6FEFF85E6FEFF85E6 + FEFF85E6FEFF84E6FEFF96EBFFFF8CD8F5FF296088B8000000004296D1FF6BBE + E8FF6DBDE6FFBBF2FFFF75DEFDFF77DEFCFF78DEFCFF7BDFFCFF7DDFFCFF7DDF + FCFF7DDFFCFF7CDFFCFF80E0FDFFADF0FFFF4D9DD3FF0000000E4095D0FF8AD7 + F5FF44A1D8FFDDFDFFFFDAFAFFFFDBFAFFFFDEFAFFFF74DCFCFF76DBFAFF75DA + FAFF74DAFAFF74DAFAFF72D9FAFFA1E8FFFF7CBFE6FF12293A5E3E94D0FFABF0 + FFFF449DD6FF368CCBFF368CCBFF368CCBFF378BCBFF5CBEEAFF6FD9FBFF6AD6 + FAFF68D5F9FF67D4F9FF66D4F9FF82DEFCFFAAE0F6FF296088B93D92CFFFB9F4 + FFFF73DBFBFF6BCCF2FF6CCDF3FF6CCEF3FF6DCEF3FF479CD4FF56BAE9FFDAF8 + FFFFD7F6FFFFD6F6FFFFD5F6FFFFD5F7FFFFDBFCFFFF3E94D0FF3C92CFFFC0F3 + FFFF71DAFBFF74DBFBFF75DBFCFF75DBFCFF76DCFCFF73DAFAFF449CD4FF378C + CBFF368CCBFF358CCCFF348DCCFF3890CEFF3D94D0FF3E8CC2EB3B92CFFFCAF6 + FFFF69D5F9FF6CD5F9FF6BD5F9FF69D5F9FF69D5FAFF6AD7FBFF68D4FAFF5EC7 + F1FF5EC7F2FF5DC8F2FFB4E3F8FF3D94D0FF1A3B5269000000003B92CFFFD5F7 + FFFF60D1F9FF61D0F8FFB4EBFDFFD9F6FFFFDAF8FFFFDAF8FFFFDBF9FFFFDCFA + FFFFDCFAFFFFDCFBFFFFE0FFFFFF3E95D0FF0E1F2A33000000003D94D0FFDCFC + FFFFD8F7FFFFD8F7FFFFDBFAFFFF358ECDFF3991CEFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3B92CFFF3D94D0FF3880B1D700000000000000002E6991B03D94 + D0FF3A92CFFF3A92CFFF3D94D0FF367CACD20000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000002200000033000000330000 + 0033000000330000003300000033000000330000002300000000000000000000 + 0030000000330000003300000033000000337B5426B9B78241FFB68142FFB681 + 42FFB68141FFB68142FFB68142FFB78343FF805C2FC00000000000000000A8A8 + A6F2AFAFADFFAEAEABFFAEAFADFFAEB3B8FFB67C35FFF8CB85FFF4C47AFFF3C3 + 77FFF3C174FFF3C377FFF4C47AFFF9CC87FFB78243FF0000000000000000B0B0 + ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB27730FFF2C787FFEAB76CFFE9B3 + 65FFFFFFFFFFE9B365FFEAB76CFFF2C98AFFB68141FF0000000000000000AEAE + ABFFFFFFFFFFFDFDFCFFFDFEFEFFFFFFFFFFB0752EFFEEC78EFFE2AE61FFE0A9 + 58FFFFFFFFFFE0A958FFE2AE61FFEEC990FFB68141FF0000000000000000ADAD + ABFFFFFFFFFFF8F8F8FFF9FAFBFFFEFFFFFFB0752DFFEBC994FFDAA252FFD89D + 47FFFFFFFFFFD89D47FFDAA252FFECCA97FFB68140FF0000000000000000ADAD + ABFFFFFFFFFFF6F5F5FFF7F7F8FFFCFFFFFFB0752CFFEACA9CFFF3E4CEFFFFFF + FFFFFFFFFFFFFFFFFFFFF3E4CEFFEBCC9FFFB7813FFF0000000000000000ADAD + ABFFFFFFFFFFF3F2F2FFF4F3F4FFF8FBFFFFB0742AFFE8CA9EFFE6C79AFFE4C4 + 95FFE4C494FFE5C595FFE6C89BFFEACEA4FFB88241FF0000000000000000ADAD + ABFFFFFFFFFFF0F0EFFFF0F1F0FFF3F6F9FFCAA578FFB1742BFFB1752CFFB175 + 2BFFB1742BFFB2762DFFB57A33FFB8803CFF8F6634C40000000000000000ADAD + ABFFFFFFFFFFEEECEBFFEEEDECFFEFEFEFFFF1F3F5FFF1F5F9FFF2F5FBFFF2F6 + FBFFF2F6FBFFFFFFFFFFAEB6BDFF00000000000000000000000000000000ADAD + ABFFFFFFFFFFEAE9E9FFEBEAEAFFEBEAEAFFEAE9EAFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFAEB0B1FF00000000000000000000000000000000ADAD + ABFFFFFFFFFFE7E7E6FFE8E8E7FFE8E8E7FFE6E6E5FFFFFFFFFFCBCBCAFFA6A6 + A4FFA5A5A2FFFFFFFFFFAFAFADFF00000000000000000000000000000000AEAE + ABFFFFFFFFFFE4E3E2FFE5E4E3FFE5E4E3FFE4E3E2FFFFFFFFFFA6A6A4FFFBFB + FAFFFFFFFFFFE9E9E9FF777775AC00000000000000000000000000000000AEAE + ACFFFFFFFFFFE0DFDEFFE1DFDEFFE1DFDEFFE0DFDEFFFFFFFFFFA5A5A2FFFFFF + FFFFE7E7E8FF737371A70000000000000000000000000000000000000000AFAF + ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9E9 + E9FF717170A6000000000000000000000000000000000000000000000000A8A8 + A6EFB0B0ADFFAEAEACFFAEAEABFFAEAEABFFADAEABFFAEAEABFFAFAFADFFA2A2 + A0EA000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0023000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000230000000000000000000000006042 + 1FC08A5E2BFF895E2BFF895D2AFF895D2AFF895D29FF895C29FF895D29FF895D + 2AFF895D2AFF895E2BFF8A5E2BFF60421FC00000000000000000000000008A5E + 2BFFAE8D5BFFAA8653FFA98551FFA7824DFFA6814BFFA57F49FFA6814BFFA782 + 4DFFA98551FFAA8653FFAE8D5BFF8A5E2BFF000000000000000000000000895D + 2AFFB18E5CFFA27E4AFF9E7841FFD8C8B1FF966D32FFFFFFFFFF966D32FFD8C8 + B1FF9E7841FFA27E4AFFB18E5CFF895D2AFF000000000000000000000000895D + 2AFFB3925EFF9E7742FFD7C6B0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFD7C6B0FF9E7742FFB3925EFF895D2AFF000000000000000000000000885C + 29FFB69562FF9A723DFF91652AFFFFFFFFFFCFBBA0FF916429FFCFBBA0FFFFFF + FFFF91652AFF9A723DFFB69562FF885C29FF000000000000000000000000885C + 29FFBA9865FF956D37FFFFFFFFFFFFFFFFFF8D6125FF936931FF8D6125FFFFFF + FFFFFFFFFFFF956D37FFBA9865FF885C29FF000000000000000000000000885C + 29FFBC9C6AFF946B36FF8B5E23FFFFFFFFFFCBB89DFF8A5D21FFCBB89DFFFFFF + FFFF8B5E23FF946B36FFBC9C6AFF885C29FF000000000000000000000000885C + 29FFC1A06EFF936934FFD2C0AAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFD1BFAAFF926833FFC1A06EFF885C29FF000000000000000000000000885C + 29FFC4A373FF916834FF8E632DFFD2C0A9FF86581DFFFFFFFFFF84551AFFCEBC + A5FF8B5F29FF8E6530FFC3A271FF875C28FF000000000000000000000000875C + 28FFC8A777FF906633FF916833FF906631FF8F642FFF8C602AFF9F7843FFC3A0 + 6DFFC4A270FFC4A271FFC6A474FF875B28FF000000000000000000000000875B + 28FFCAAB7BFF8E6330FF916734FF926734FF916633FF8D622FFFC9A978FF9A72 + 3EFF7E4F18FF7D4E18FFC8A876FF875B28FF000000000000000000000000875B + 28FFCEAF7EFF8A5F2CFF8D6330FF8E6431FF8D6330FF8A5F2CFFCCAD7BFF7E4F + 18FFF6FFFFFFFFFFFFFFAF8956FF5C3E1CAC000000000000000000000000875B + 28FFD1B181FF845824FF875B27FF885C28FF875B27FF845724FFCEAD7DFF7C4D + 16FFFFFFFFFFAE8651FF573A17A700000000000000000000000000000000885C + 29FFD5B687FFD4B585FFD4B586FFD5B586FFD4B586FFD3B485FFD1B282FFD1B2 + 81FFB38E59FF573917A600000000000000000000000000000000000000008159 + 29EF885C29FF875B28FF875B28FF875B28FF875B28FF865B27FF865A27FF875B + 27FF7D5426EA0000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000230000 + 0033000000330000003300000033000000330000003300000033000000330000 + 00330000003300000033000000230000000000000000000000007B7B7AC0AFAF + ADFFAEAEACFFAEAEACFFAEAFADFFAFB0AEFFAFB0AFFFAFB0AEFFAFAFAEFFAFAF + ADFFAFAFADFFB0B0AEFF7B7B79BF000000000000000000000000B0B0ADFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFB1B1AEFF000000330000003300000023AEAEABFFFFFF + FFFFFFFFFFFFF7F3EFFFC38450FFA54800FFA64900FFA74900FFAA6B37FFACA8 + A2FFABAFB0FFABACAAFFADADABFFAFAFADFFB0B1AEFF7B7B7AC0AEAEACFFFFFF + FFFFF5EFECFFAB5308FFC8843EFFE4B270FFE3AF6DFFE5B271FFCB8741FFAF57 + 0DFFEFE9E6FFF5F7FAFFF4F5F6FFF6F7F8FFFFFFFFFFB0B1AEFFAEAFADFFFFFF + FFFFC1844EFFC67F38FFDEA865FFDAA15BFFFFFFFFFFDAA25BFFDEA966FFC881 + 3AFFBE814DFFFFFFFFFFFFFFFFFFB48C75FFFFFFFFFFAFB0AEFFAFAFAEFFFFFF + FFFFA64900FFD89F5AFFD69C57FFD3944CFFFFFFFFFFD3944CFFD69C57FFD9A0 + 5BFFA94E00FFB89687FFB7907CFFB68E79FFFFFFFFFFAFAFADFFAFB0AFFFFFFF + FFFFA74A00FFDCAB71FFD19149FFCF8C41FFFFFFFFFFCF8C41FFD19149FFDDAB + 72FFA94D00FFDEE8EFFFDCE0E2FFDCDFDFFFFFFFFFFFAFAFADFFAFAFAEFFFFFF + FFFFA64800FFE8CAA5FFCB8639FFCA8436FFC88130FFCA8436FFCB8639FFE9CB + A6FFA84B00FFFFFFFFFFFFFFFFFFB58D76FFFFFFFFFFAFAFADFFAEAFADFFFFFF + FFFFBD7E48FFCF9763FFE0B789FFC88236FFFFFFFFFFC88236FFE0B78AFFD099 + 65FFB47641FFB79381FFB68E7AFFB68D77FFFFFFFFFFAFB0AEFFAEAEACFFFFFF + FFFFE5DFDBFFAA5206FFCC945EFFE9CBAAFFE8C9A7FFE9CBABFFCE9660FFAF56 + 0BFFF8F4F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0B0AEFFAEAEABFFFFFF + FFFFE9ECEEFFE4DEDAFFBD7E47FFA74800FFA74900FFA84900FFAC6D37FFAEA9 + A2FFACAFB0FFACADACFFAEAFADFFAFAFADFFB0B0AEFF7C7C7AB0AEAEABFFFFFF + FFFFE3E5E4FFE6E9EAFFE8EDF1FFE9F0F5FFE8F0F5FFFFFFFFFFAAB0B2FFEDF0 + F1FFFFFFFFFFEBEBECFF727271A4000000000000000000000000AEAEACFFFFFF + FFFFE0DFDEFFE1E0DFFFE1E1E1FFE1E2E1FFE1E1E1FFFFFFFFFFA6A7A5FFFFFF + FFFFE8E8E8FF737371A700000000000000000000000000000000AFAFADFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9E9 + E9FF717170A60000000000000000000000000000000000000000A8A8A6EFB0B0 + ADFFAEAEACFFAEAEABFFAEAEABFFAEAEABFFADAEABFFAEAEABFFAFAFADFFA2A2 + A0EA000000000000000000000000000000000000000000000000} + end> + end +end diff --git a/assets/InstructionEditor/Forms/Editors/formEditorCPUIDFeatureFlags.pas b/assets/InstructionEditor/Forms/Editors/formEditorCPUIDFeatureFlags.pas new file mode 100644 index 0000000..ff02155 --- /dev/null +++ b/assets/InstructionEditor/Forms/Editors/formEditorCPUIDFeatureFlags.pas @@ -0,0 +1,191 @@ +unit formEditorCPUIDFeatureFlags; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, untInstructionEditor, cxOI, Vcl.StdCtrls, System.ImageList, + Vcl.ImgList, cxGraphics, VirtualTrees; + +type + TfrmEditorCPUIDFeatureFlags = class(TForm) + GroupBox: TGroupBox; + btnCancel: TButton; + imgIcons16: TcxImageList; + btnApply: TButton; + VirtualTreeView: TVirtualStringTree; + imgTreeView: TcxImageList; + procedure btnApplyClick(Sender: TObject); + procedure btnCancelClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure VirtualTreeViewChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure VirtualTreeViewCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; + var Allowed: Boolean); + procedure VirtualTreeViewFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure VirtualTreeViewGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure VirtualTreeViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + strict private + FApplyChanges: Boolean; + FFeatureFlags: TCPUIDFeatureFlagSet; + strict private + procedure SetFeatureFlags(const Value: TCPUIDFeatureFlagSet); + public + property ApplyChanges: Boolean read FApplyChanges; + property FeatureFlags: TCPUIDFeatureFlagSet read FFeatureFlags write SetFeatureFlags; + end; + +var + frmEditorCPUIDFeatureFlags: TfrmEditorCPUIDFeatureFlags; + +implementation + +uses + System.TypInfo; + +{$R *.dfm} + +type + PNodeData = ^TNodeData; + TNodeData = record + public + Text: String; + Value: TCPUIDFeatureFlag; + end; + +procedure TfrmEditorCPUIDFeatureFlags.btnApplyClick(Sender: TObject); +begin + FApplyChanges := true; + Close; +end; + +procedure TfrmEditorCPUIDFeatureFlags.btnCancelClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmEditorCPUIDFeatureFlags.FormCreate(Sender: TObject); +var + Root, + Node: PVirtualNode; + NodeData: PNodeData; + C: TCPUIDFeatureFlag; + S: String; +begin + FFeatureFlags := []; + VirtualTreeView.NodeDataSize := SizeOf(TNodeData); + VirtualTreeView.BeginUpdate; + try + Root := VirtualTreeView.AddChild(nil); + NodeData := VirtualTreeView.GetNodeData(Root); + NodeData^.Text := 'CPUID Feature Flags'; + for C := Low(TCPUIDFeatureFlag) to High(TCPUIDFeatureFlag) do + begin + Node := VirtualTreeView.AddChild(Root); + VirtualTreeView.CheckType[Node] := ctCheckBox; + NodeData := VirtualTreeView.GetNodeData(Node); + S := GetEnumName(TypeInfo(TCPUIDFeatureFlag), Ord(C)); + Delete(S, 1, 2); + NodeData^.Text := S; + NodeData^.Value := C; + end; + VirtualTreeView.Expanded[Root] := true; + finally + VirtualTreeView.EndUpdate; + end; +end; + +procedure TfrmEditorCPUIDFeatureFlags.SetFeatureFlags(const Value: TCPUIDFeatureFlagSet); +var + Node: PVirtualNode; + NodeData: PNodeData; +begin + VirtualTreeView.BeginUpdate; + try + Node := VirtualTreeView.GetFirst; + while (Assigned(Node)) do + begin + NodeData := VirtualTreeView.GetNodeData(Node); + if (Assigned(NodeData) and (Node.Parent <> VirtualTreeView.RootNode)) then + begin + if (NodeData^.Value in Value) then + begin + VirtualTreeView.CheckState[Node] := csCheckedNormal; + end else + begin + VirtualTreeView.CheckState[Node] := csUncheckedNormal; + end; + end; + Node := VirtualTreeView.GetNext(Node); + end; + finally + VirtualTreeView.EndUpdate; + end; +end; + +procedure TfrmEditorCPUIDFeatureFlags.VirtualTreeViewChecked(Sender: TBaseVirtualTree; + Node: PVirtualNode); +var + NodeData: PNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + case Sender.CheckState[Node] of + csCheckedNormal: + FFeatureFlags := FFeatureFlags + [NodeData^.Value]; + csUncheckedNormal: + FFeatureFlags := FFeatureFlags - [NodeData^.Value]; + end; + end; +end; + +procedure TfrmEditorCPUIDFeatureFlags.VirtualTreeViewCollapsing(Sender: TBaseVirtualTree; + Node: PVirtualNode; var Allowed: Boolean); +begin + Allowed := false; +end; + +procedure TfrmEditorCPUIDFeatureFlags.VirtualTreeViewFreeNode(Sender: TBaseVirtualTree; + Node: PVirtualNode); +var + NodeData: PNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + Finalize(NodeData^); + end; +end; + +procedure TfrmEditorCPUIDFeatureFlags.VirtualTreeViewGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; + var ImageIndex: Integer); +begin + ImageIndex := -1; + if (Kind in [ikNormal, ikSelected]) then + begin + if (Node.Parent = Sender.RootNode) then + begin + ImageIndex := 0; + end else + begin + ImageIndex := 1; + end; + end; +end; + +procedure TfrmEditorCPUIDFeatureFlags.VirtualTreeViewGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + NodeData: PNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + CellText := NodeData^.Text; + end; +end; + +end. diff --git a/assets/InstructionEditor/Forms/Editors/formEditorInstructionOperands.dfm b/assets/InstructionEditor/Forms/Editors/formEditorInstructionOperands.dfm new file mode 100644 index 0000000..9c8ac05 --- /dev/null +++ b/assets/InstructionEditor/Forms/Editors/formEditorInstructionOperands.dfm @@ -0,0 +1,199 @@ +object frmEditorInstructionOperands: TfrmEditorInstructionOperands + Left = 0 + Top = 0 + BorderStyle = bsDialog + Caption = 'frmEditorInstructionOperands' + ClientHeight = 462 + ClientWidth = 640 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + OnDestroy = FormDestroy + PixelsPerInch = 96 + TextHeight = 13 + object GroupBox: TGroupBox + AlignWithMargins = True + Left = 3 + Top = 420 + Width = 634 + Height = 39 + Margins.Top = 0 + Align = alBottom + TabOrder = 0 + DesignSize = ( + 634 + 39) + object btnCancel: TButton + Left = 514 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Cancel' + ImageIndex = 1 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 1 + OnClick = btnCancelClick + end + object btnApply: TButton + Left = 396 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Apply' + ImageIndex = 0 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 0 + OnClick = btnApplyClick + end + end + object PageControl1: TPageControl + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 634 + Height = 414 + ActivePage = TabSheet1 + Align = alClient + TabOrder = 1 + object TabSheet1: TTabSheet + Caption = 'Instruction Operands' + object GroupBox1: TGroupBox + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 238 + Height = 380 + Align = alLeft + TabOrder = 0 + end + end + end + object imgIcons16: TcxImageList + FormatVersion = 1 + DesignInfo = 1049152 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 20000000000000040000000000000000000000000000000000000000001B0000 + 0033000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000001B00000000004B29A00089 + 49FF008747FF008747FF008747FF008747FF008747FF008747FF008747FF0087 + 47FF008747FF008747FF008747FF008949FF004B29A000000000008949FF07E4 + A4FF07E5A5FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4 + A4FF07E4A4FF07E4A4FF07E5A5FF07E4A4FF008949FF00000000008747FF13E7 + AAFF00DB9BFF00DA9AFF00DA99FF00DA99FF00DA99FF00DA99FF00DA9AFF00DA + 9AFF00DA9AFF00DA9AFF00DB9BFF13E7AAFF008747FF00000000008746FF1EE7 + AEFF00D699FF00D698FF00D495FF00D391FF00D391FF00D495FF00D698FF00D6 + 99FF00D699FF00D699FF00D699FF1EE7AEFF008746FF00000000008746FF2AE9 + B3FF00D299FF00D095FF00CC8DFFFFFFFFFFFFFFFFFF00CC8DFF00D096FF00D2 + 99FF00D29AFF00D29AFF00D29AFF2AE9B3FF008746FF00000000008746FF35EA + B7FF00CD96FF00C98DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C98DFF00CD + 96FF00CF99FF00CF9AFF00CF9AFF36EAB8FF008746FF00000000008745FF3EEB + BBFF00C692FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C4 + 8DFF00C995FF00CA99FF00CA99FF41ECBDFF008745FF00000000008745FF4BED + BFFF00C393FFFFFFFFFFFFFFFFFF00C08BFF00BF8BFFFFFFFFFFFFFFFFFFFFFF + FFFF00C18EFF00C596FF00C699FF4DEDC0FF008745FF00000000008744FF58EF + C5FF00C197FF00BF93FF00C093FF00C196FF00C196FF00BC8EFFFFFFFFFFFFFF + FFFFFFFFFFFF00BC8EFF00C096FF58EFC5FF008744FF00000000008744FF64F1 + CAFF00BE99FF00C099FF00C09AFF00C19BFF00C19AFF00BE97FF00B98EFFFFFF + FFFFFFFFFFFFFFFFFFFF00BA92FF62F0C9FF008744FF00000000008744FF71F2 + CFFF00BB99FF00BD9AFF00BE9BFF00BE9BFF00BE9BFF00BE9AFF00BB96FF00B6 + 8EFFFFFFFFFFFFFFFFFF00B792FF6EF2CDFF008744FF00000000008744FF7BF4 + D3FF00B699FF00B89AFF00B99BFF00B99BFF00B99BFF00B99BFF00B89AFF00B7 + 98FF00B494FF00B493FF00B496FF7AF3D3FF008744FF00000000008744FF86F5 + D8FF00B198FF00B299FF00B399FF00B399FF00B399FF00B399FF00B399FF00B2 + 99FF00B298FF00B297FF00B197FF86F5D8FF008744FF00000000008946FF8AF2 + D9FF92F6DEFF93F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6 + DDFF94F6DDFF93F6DDFF92F6DEFF8AF2D9FF008946FF00000000004B29880089 + 46FF008743FF008643FF008643FF008643FF008643FF008643FF008643FF0086 + 43FF008643FF008643FF008743FF008946FF004B298800000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0013000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000003300000013000000001117 + 487E2D3CC0FF2B3BBEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3A + BEFF2A3ABEFF2A3ABEFF2A3ABEFF2B3BBEFF2D3CC0FF1117487E000000002D3D + C0FF6172FAFF6A7DFFFF697CFFFF6D80FFFF7485FFFF7788FFFF7788FFFF7788 + FFFF7485FFFF6D7FFFFF697CFFFF6A7DFFFF6172FAFF2D3DC0FF000000002B3B + BEFF6578FFFF5F73FEFF6F80FFFF7989FFFF5868E6FF3E4ED0FF3F4FD1FF3E4E + D0FF5767E5FF7887FEFF6E7FFFFF5F73FEFF6578FFFF2B3BBEFF000000002B3B + BEFF5D72FFFF697BFEFF7785F8FF3949CAFF1E2A89B70B0F303F07091D26070A + 1F552636B9FF5A6FFDFF576CFAFF687AFCFF5D71FFFF2B3BBEFF000000002C3B + BFFF586EFEFF8593FFFF3B4BCAFF0E143F530000000000000000000000332B3A + BDFF5970FEFF546AFBFF7F8FFFFF8290FDFF586EFEFF2C3BBFFF000000002C3C + BFFF536BFCFF707CE7FF1E2A89BB0000000000000000000000332C3BBEFF546B + FBFF5067F8FF8796FFFF3B4BCDFF6D79E5FF536AFCFF2C3CBFFF000000002D3D + BFFF4F68FBFF4E5BD1FF0B0F304500000000000000332C3BBEFF4E66F9FF4A63 + F6FF8C99FFFF2737BCFF07091F314D5AD0FF4F68FBFF2D3DBFFF000000002E3D + C0FF4A64F9FF3446CDFF07091D2D000000332D3CBEFF4862F7FF445DF4FF8E9C + FFFF2838BDFF0000000007091D313446CDFF4A64F9FF2E3DC0FF000000002E3D + C0FF4660F7FF3445CCFF080A20552D3CBEFF445DF4FF3F59F1FF929FFFFF2838 + BDFF00000000000000000C0F305B3445CDFF4660F7FF2E3DC0FF000000002E3E + C0FF405BF3FF384DDBFF2E3CBCFF3E59F2FF3954EFFF95A2FFFF2838BDFF0000 + 00000000000000000011222D8AC5384EDCFF405BF3FF2E3EC0FF000000002F3E + C0FF3955F0FF3951EAFF3954EEFF3651EDFF9AA5FFFF2838BDFF000000080000 + 000D0000002510153F753041C8FF3A53EBFF3A55F0FF2F3EC0FF000000002E3D + BFFF3A54EFFF324DE9FF334DE9FF324DEBFF2A39BCFF070A1F5507091D510B0F + 3065212D8AC52F41C8FF314CE4FF324DEBFF3A54EFFF2E3DBFFF000000002B3B + BFFF6A7DFDFF334EE8FF2643E4FF2642E3FF253CD4FF2739C7FF273AC8FF273A + C8FF263DD5FF2743E5FF2643E6FF334EE9FF6A7DFDFF2B3BBFFF000000002B3B + C0FF929DFCFFAAB3FFFFAAB3FFFFAAB3FFFFAAB4FFFFAAB4FFFFAAB4FFFFAAB4 + FFFFAAB4FFFFAAB3FFFFAAB3FFFFAAB3FFFF929DFCFF2B3BC0FF000000001117 + 485E2A3AC0FF2838BFFF2737BEFF2737BEFF2737BEFF2737BFFF2737BFFF2737 + BFFF2737BEFF2737BEFF2737BEFF2838BFFF2A3AC0FF1117485E} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000300000 + 0033000000330000003300000033000000330000003300000033000000330000 + 00330000002F0000000000000000000000000000000000000000A36B31F2AB6E + 31FFAA6B2DFFAA6C2FFFAA6D31FFAA6D31FFAA6D31FFAA6C2FFFAA6B2DFFAB6E + 31FFA26A31F10000000000000000000000000000000000000000AB6E31FFEEAF + 60FFFFF7DEFFE9A95BFFEAAB5EFFEAAB5FFFEAAB5EFFE9A95AFFFFF7DEFFEEAF + 60FFAB6E30FF0000003300000033000000330000003300000023AA6B2DFFFFF6 + DDFFFCEDD2FFFCEFD5FFFDF1D9FFFDF0D7FFFCEED4FFFCEDD2FFFCEDD1FFFFF6 + DDFFA8692BFFAB6E31FFAA6C2FFFAA6B2DFFAB6E2FFF784F24C0AA6C2EFFE8B0 + 68FFFDEED4FFDD9C4FFFDEA054FFDD9E52FFFDEFD6FFDA9747FFFCEDD1FFE7AE + 67FFA56628FFEEAF62FFEAA95BFFFFF6DCFFF4C180FFAB6D2FFFAA6C2FFFE7B4 + 72FFFEF1D8FFD99C52FFDBA159FFDBA058FFD99C51FFFDEFD5FFFCEDD2FFE6B2 + 6FFFA36324FFFFF5DCFFFCEDD2FFFCECCFFFFFF5DAFFA96B2CFFAA6C2FFFE8B7 + 78FFFEF1D8FFD59A53FFD89F5AFFD89F5BFFD69C56FFDDAD70FFFEEFD5FFE7B5 + 76FFA46324FFFFF4DBFFE2AC68FFFBEBCEFFF2CC98FFAA6B2CFFAA6C2FFFE7B9 + 7FFFFFF1D7FFD0954FFFD39B57FFD39B58FFD29A55FFD0954EFFFFF3DAFFE6B9 + 7FFFA56627FFDDA054FFFDF0D6FFFCECD1FFEEC189FFAA6B2DFFAA6C2EFFE7BB + 84FFFEF0D5FFCA8F4AFFCD9552FFD7A668FFE8BF8BFFE8BE89FFE6BC86FFE9BF + 8AFFA6672AFFDAA05AFFD4974EFFFDEFD4FFEEC590FFAA6B2DFFAA6C2EFFE5BD + 8AFFFDEED2FFFFF1D6FFC58D48FFE6C08EFFBF894FFFA66728FFA56426FFE9C5 + 94FFA6672AFFD59D58FFD1964FFFFFF2D9FFEECA96FFAA6C2EFFAA6B2CFFE5C0 + 8EFFFDECD0FFBB813AFFFFF0D5FFECCDA3FFA56526FFDBA25AFFE8C89CFFCFA2 + 6EFFBF894DFFE9C18DFFE8BF8AFFE6BC86FFE9C08AFFAB6D2FFFAA6B2BFFFFF5 + DAFFFDECCEFFFDECCFFFFEEED2FFEBCEA6FFA56322FFE8CAA0FFCEA16EFFB173 + 31FFE8C390FFC08950FFA66728FFA56426FFEBC695FFAC6E30FFAB6D2EFFE6CB + A3FFFFF5D9FFE2C59AFFE3C69DFFE5C9A1FFE7CCA4FFCDA371FFAE6E2AFFFFF4 + DAFFE6C392FFA66627FFDCA35AFFE9CA9EFFD3A773FF754C22AC784E24B0AB6D + 2EFFAA6B2BFFAA6B2BFFAA6B2CFFAA6A2AFFA76524FFC79865FFFFF3D7FFFFF0 + D4FFE4C396FFA56323FFE9CCA2FFD2A775FF70481FA700000000000000000000 + 0000000000000000000000000000AD6F31FFE9D0A9FFFFF9DFFFE3C69CFFE3C7 + 9EFFE6CAA2FFE8CFA7FFD1AA7AFF70471FA70000000000000000000000000000 + 0000000000000000000000000000774E24AFAB6C2EFFC18E58FFA9692AFFAA6B + 2CFFAB6C2EFFAC6D2FFF754B21AC000000000000000000000000} + end> + end +end diff --git a/assets/InstructionEditor/Forms/Editors/formEditorInstructionOperands.pas b/assets/InstructionEditor/Forms/Editors/formEditorInstructionOperands.pas new file mode 100644 index 0000000..2fa93b7 --- /dev/null +++ b/assets/InstructionEditor/Forms/Editors/formEditorInstructionOperands.pas @@ -0,0 +1,80 @@ +unit formEditorInstructionOperands; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, System.ImageList, Vcl.ImgList, cxGraphics, + Vcl.StdCtrls, untInstructionEditor; + +type + TfrmEditorInstructionOperands = class(TForm) + GroupBox: TGroupBox; + btnCancel: TButton; + btnApply: TButton; + imgIcons16: TcxImageList; + PageControl1: TPageControl; + TabSheet1: TTabSheet; + GroupBox1: TGroupBox; + procedure FormCreate(Sender: TObject); + procedure btnCancelClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure btnApplyClick(Sender: TObject); + strict private + FApplyChanges: Boolean; + FEditor: TInstructionEditor; + FDefinition: TInstructionDefinition; + strict private + function GetOperands: TInstructionOperands; inline; + procedure SetOperands(const Value: TInstructionOperands); inline; + public + property ApplyChanges: Boolean read FApplyChanges; + property Operands: TInstructionOperands read GetOperands write SetOperands; + end; + +var + frmEditorInstructionOperands: TfrmEditorInstructionOperands; + +implementation + +{$R *.dfm} + +{ TfrmEditorInstructionOperands } + +procedure TfrmEditorInstructionOperands.btnApplyClick(Sender: TObject); +begin + FApplyChanges := true; + Close; +end; + +procedure TfrmEditorInstructionOperands.btnCancelClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmEditorInstructionOperands.FormCreate(Sender: TObject); +begin + FEditor := TInstructionEditor.Create; + FEditor.Reset; + FDefinition := FEditor.CreateDefinition('dummy'); +end; + +procedure TfrmEditorInstructionOperands.FormDestroy(Sender: TObject); +begin + if (Assigned(FEditor)) then + begin + FEditor.Free; + end; +end; + +function TfrmEditorInstructionOperands.GetOperands: TInstructionOperands; +begin + Result := FDefinition.Operands; +end; + +procedure TfrmEditorInstructionOperands.SetOperands(const Value: TInstructionOperands); +begin + FDefinition.Operands.Assign(Value); +end; + +end. diff --git a/assets/InstructionEditor/Forms/Editors/formEditorX86Registers.dfm b/assets/InstructionEditor/Forms/Editors/formEditorX86Registers.dfm new file mode 100644 index 0000000..8b036fe --- /dev/null +++ b/assets/InstructionEditor/Forms/Editors/formEditorX86Registers.dfm @@ -0,0 +1,244 @@ +object frmEditorX86Registers: TfrmEditorX86Registers + Left = 0 + Top = 0 + BorderStyle = bsDialog + Caption = 'frmEditorX86Registers' + ClientHeight = 421 + ClientWidth = 594 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object GroupBox: TGroupBox + AlignWithMargins = True + Left = 3 + Top = 379 + Width = 588 + Height = 39 + Margins.Top = 0 + Align = alBottom + TabOrder = 1 + DesignSize = ( + 588 + 39) + object btnCancel: TButton + Left = 468 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Cancel' + ImageIndex = 1 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 1 + OnClick = btnCancelClick + end + object btnApply: TButton + Left = 350 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Apply' + ImageIndex = 0 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 0 + OnClick = btnApplyClick + end + end + object VirtualTreeView: TVirtualStringTree + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 588 + Height = 373 + Align = alClient + Header.AutoSizeIndex = -1 + Header.Font.Charset = DEFAULT_CHARSET + Header.Font.Color = clWindowText + Header.Font.Height = -11 + Header.Font.Name = 'Tahoma' + Header.Font.Style = [] + Header.MainColumn = -1 + Images = imgTreeView + TabOrder = 0 + TreeOptions.MiscOptions = [toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toAlwaysHideSelection, toUseBlendedSelection] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnChecked = VirtualTreeViewChecked + OnCollapsing = VirtualTreeViewCollapsing + OnFreeNode = VirtualTreeViewFreeNode + OnGetText = VirtualTreeViewGetText + OnGetImageIndex = VirtualTreeViewGetImageIndex + Columns = <> + end + object imgIcons16: TcxImageList + FormatVersion = 1 + DesignInfo = 2097208 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 20000000000000040000000000000000000000000000000000000000001B0000 + 0033000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000001B00000000004B29A00089 + 49FF008747FF008747FF008747FF008747FF008747FF008747FF008747FF0087 + 47FF008747FF008747FF008747FF008949FF004B29A000000000008949FF07E4 + A4FF07E5A5FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4 + A4FF07E4A4FF07E4A4FF07E5A5FF07E4A4FF008949FF00000000008747FF13E7 + AAFF00DB9BFF00DA9AFF00DA99FF00DA99FF00DA99FF00DA99FF00DA9AFF00DA + 9AFF00DA9AFF00DA9AFF00DB9BFF13E7AAFF008747FF00000000008746FF1EE7 + AEFF00D699FF00D698FF00D495FF00D391FF00D391FF00D495FF00D698FF00D6 + 99FF00D699FF00D699FF00D699FF1EE7AEFF008746FF00000000008746FF2AE9 + B3FF00D299FF00D095FF00CC8DFFFFFFFFFFFFFFFFFF00CC8DFF00D096FF00D2 + 99FF00D29AFF00D29AFF00D29AFF2AE9B3FF008746FF00000000008746FF35EA + B7FF00CD96FF00C98DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C98DFF00CD + 96FF00CF99FF00CF9AFF00CF9AFF36EAB8FF008746FF00000000008745FF3EEB + BBFF00C692FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C4 + 8DFF00C995FF00CA99FF00CA99FF41ECBDFF008745FF00000000008745FF4BED + BFFF00C393FFFFFFFFFFFFFFFFFF00C08BFF00BF8BFFFFFFFFFFFFFFFFFFFFFF + FFFF00C18EFF00C596FF00C699FF4DEDC0FF008745FF00000000008744FF58EF + C5FF00C197FF00BF93FF00C093FF00C196FF00C196FF00BC8EFFFFFFFFFFFFFF + FFFFFFFFFFFF00BC8EFF00C096FF58EFC5FF008744FF00000000008744FF64F1 + CAFF00BE99FF00C099FF00C09AFF00C19BFF00C19AFF00BE97FF00B98EFFFFFF + FFFFFFFFFFFFFFFFFFFF00BA92FF62F0C9FF008744FF00000000008744FF71F2 + CFFF00BB99FF00BD9AFF00BE9BFF00BE9BFF00BE9BFF00BE9AFF00BB96FF00B6 + 8EFFFFFFFFFFFFFFFFFF00B792FF6EF2CDFF008744FF00000000008744FF7BF4 + D3FF00B699FF00B89AFF00B99BFF00B99BFF00B99BFF00B99BFF00B89AFF00B7 + 98FF00B494FF00B493FF00B496FF7AF3D3FF008744FF00000000008744FF86F5 + D8FF00B198FF00B299FF00B399FF00B399FF00B399FF00B399FF00B399FF00B2 + 99FF00B298FF00B297FF00B197FF86F5D8FF008744FF00000000008946FF8AF2 + D9FF92F6DEFF93F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6 + DDFF94F6DDFF93F6DDFF92F6DEFF8AF2D9FF008946FF00000000004B29880089 + 46FF008743FF008643FF008643FF008643FF008643FF008643FF008643FF0086 + 43FF008643FF008643FF008743FF008946FF004B298800000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0013000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000003300000013000000001117 + 487E2D3CC0FF2B3BBEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3A + BEFF2A3ABEFF2A3ABEFF2A3ABEFF2B3BBEFF2D3CC0FF1117487E000000002D3D + C0FF6172FAFF6A7DFFFF697CFFFF6D80FFFF7485FFFF7788FFFF7788FFFF7788 + FFFF7485FFFF6D7FFFFF697CFFFF6A7DFFFF6172FAFF2D3DC0FF000000002B3B + BEFF6578FFFF5F73FEFF6F80FFFF7989FFFF5868E6FF3E4ED0FF3F4FD1FF3E4E + D0FF5767E5FF7887FEFF6E7FFFFF5F73FEFF6578FFFF2B3BBEFF000000002B3B + BEFF5D72FFFF697BFEFF7785F8FF3949CAFF1E2A89B70B0F303F07091D26070A + 1F552636B9FF5A6FFDFF576CFAFF687AFCFF5D71FFFF2B3BBEFF000000002C3B + BFFF586EFEFF8593FFFF3B4BCAFF0E143F530000000000000000000000332B3A + BDFF5970FEFF546AFBFF7F8FFFFF8290FDFF586EFEFF2C3BBFFF000000002C3C + BFFF536BFCFF707CE7FF1E2A89BB0000000000000000000000332C3BBEFF546B + FBFF5067F8FF8796FFFF3B4BCDFF6D79E5FF536AFCFF2C3CBFFF000000002D3D + BFFF4F68FBFF4E5BD1FF0B0F304500000000000000332C3BBEFF4E66F9FF4A63 + F6FF8C99FFFF2737BCFF07091F314D5AD0FF4F68FBFF2D3DBFFF000000002E3D + C0FF4A64F9FF3446CDFF07091D2D000000332D3CBEFF4862F7FF445DF4FF8E9C + FFFF2838BDFF0000000007091D313446CDFF4A64F9FF2E3DC0FF000000002E3D + C0FF4660F7FF3445CCFF080A20552D3CBEFF445DF4FF3F59F1FF929FFFFF2838 + BDFF00000000000000000C0F305B3445CDFF4660F7FF2E3DC0FF000000002E3E + C0FF405BF3FF384DDBFF2E3CBCFF3E59F2FF3954EFFF95A2FFFF2838BDFF0000 + 00000000000000000011222D8AC5384EDCFF405BF3FF2E3EC0FF000000002F3E + C0FF3955F0FF3951EAFF3954EEFF3651EDFF9AA5FFFF2838BDFF000000080000 + 000D0000002510153F753041C8FF3A53EBFF3A55F0FF2F3EC0FF000000002E3D + BFFF3A54EFFF324DE9FF334DE9FF324DEBFF2A39BCFF070A1F5507091D510B0F + 3065212D8AC52F41C8FF314CE4FF324DEBFF3A54EFFF2E3DBFFF000000002B3B + BFFF6A7DFDFF334EE8FF2643E4FF2642E3FF253CD4FF2739C7FF273AC8FF273A + C8FF263DD5FF2743E5FF2643E6FF334EE9FF6A7DFDFF2B3BBFFF000000002B3B + C0FF929DFCFFAAB3FFFFAAB3FFFFAAB3FFFFAAB4FFFFAAB4FFFFAAB4FFFFAAB4 + FFFFAAB4FFFFAAB3FFFFAAB3FFFFAAB3FFFF929DFCFF2B3BC0FF000000001117 + 485E2A3AC0FF2838BFFF2737BEFF2737BEFF2737BEFF2737BFFF2737BFFF2737 + BFFF2737BEFF2737BEFF2737BEFF2838BFFF2A3AC0FF1117485E} + end> + end + object imgTreeView: TcxImageList + FormatVersion = 1 + DesignInfo = 2097288 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000300000 + 0033000000330000003300000033000000330000003300000033000000330000 + 00330000003300000033000000330000002F00000000000000004190C6F24398 + D2FF4094D0FF3E92CFFF3E92CEFF3F92CEFF3F92CEFF3F92CEFF3F92CEFF3F92 + CEFF3F92CEFF3F92CEFF3F93CFFF3D8BC2F00000000E000000004499D2FF3F94 + D0FFABFBFFFF9BF3FFFF92F1FFFF93F1FFFF93F1FFFF93F1FFFF93F1FFFF93F1 + FFFF93F1FFFF93F1FFFFA6F8FFFF65B8E3FF122A3A5F000000004398D2FF4FA6 + D9FF8EDAF5FFA2EEFFFF82E5FEFF84E5FEFF84E5FEFF85E6FEFF85E6FEFF85E6 + FEFF85E6FEFF84E6FEFF96EBFFFF8CD8F5FF296088B8000000004296D1FF6BBE + E8FF6DBDE6FFBBF2FFFF75DEFDFF77DEFCFF78DEFCFF7BDFFCFF7DDFFCFF7DDF + FCFF7DDFFCFF7CDFFCFF80E0FDFFADF0FFFF4D9DD3FF0000000E4095D0FF8AD7 + F5FF44A1D8FFDDFDFFFFDAFAFFFFDBFAFFFFDEFAFFFF74DCFCFF76DBFAFF75DA + FAFF74DAFAFF74DAFAFF72D9FAFFA1E8FFFF7CBFE6FF12293A5E3E94D0FFABF0 + FFFF449DD6FF368CCBFF368CCBFF368CCBFF378BCBFF5CBEEAFF6FD9FBFF6AD6 + FAFF68D5F9FF67D4F9FF66D4F9FF82DEFCFFAAE0F6FF296088B93D92CFFFB9F4 + FFFF73DBFBFF6BCCF2FF6CCDF3FF6CCEF3FF6DCEF3FF479CD4FF56BAE9FFDAF8 + FFFFD7F6FFFFD6F6FFFFD5F6FFFFD5F7FFFFDBFCFFFF3E94D0FF3C92CFFFC0F3 + FFFF71DAFBFF74DBFBFF75DBFCFF75DBFCFF76DCFCFF73DAFAFF449CD4FF378C + CBFF368CCBFF358CCCFF348DCCFF3890CEFF3D94D0FF3E8CC2EB3B92CFFFCAF6 + FFFF69D5F9FF6CD5F9FF6BD5F9FF69D5F9FF69D5FAFF6AD7FBFF68D4FAFF5EC7 + F1FF5EC7F2FF5DC8F2FFB4E3F8FF3D94D0FF1A3B5269000000003B92CFFFD5F7 + FFFF60D1F9FF61D0F8FFB4EBFDFFD9F6FFFFDAF8FFFFDAF8FFFFDBF9FFFFDCFA + FFFFDCFAFFFFDCFBFFFFE0FFFFFF3E95D0FF0E1F2A33000000003D94D0FFDCFC + FFFFD8F7FFFFD8F7FFFFDBFAFFFF358ECDFF3991CEFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3B92CFFF3D94D0FF3880B1D700000000000000002E6991B03D94 + D0FF3A92CFFF3A92CFFF3D94D0FF367CACD20000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000330000000000000033000000000000003300000000000000330000 + 000000000033000000000000003300000000000000330000000C000000000000 + 0000519DD5FF00000005519DD3FF00000005519DD3FF00000005519DD3FF0000 + 0005519DD3FF00000005519DD3FF000000055299CBFF14253046000000000000 + 002E50A0D9FF0A090947509FD8FF0A090947509FD8FF0A090947509FD8FF0A09 + 0947509FD8FF0A090947509FD8FF0A090947519CD2FF0F1D2755000000005C5B + 5AEC666361FF676462FF676461FF676462FF676461FF676462FF676461FF6764 + 62FF676461FF676462FF676461FF676361FF67625EFF5D5653EA000000006565 + 65FF625F5DFF585554FF585554FF585554FF585554FF585554FF585554FF5855 + 54FF585554FF585654FF595655FF585554FF625E5DFF656564FF000000006565 + 65FF6E6C6BFF52504FFF4F4D4CFF4E4C4BFF4F4C4BFF4F4D4CFF4F4D4CFF4F4D + 4CFF4F4D4CFF514F4EFF545251FF545251FF6F6C6BFF656565FF000000006364 + 64FF7B7A79FF4A4847FFC1C0C0FFB1B0AFFFA7A6A6FF878585FFCECDCDFFAAA9 + A9FF939291FFC5C4C4FF4E4C4AFF504E4DFF7C7C7AFF636464FF000000006363 + 63FF888686FF424040FFDCDCDCFFD5D6D6FFC0C0C0FFBAB9B9FF3A3838FFBBBA + BBFF747373FFCDCCCCFF494747FF4C4A4AFF8A8888FF636363FF000000006262 + 62FF969595FF403E3EFFE1E0E0FFCFCECEFFC5C4C4FFA5A3A3FFA7A7A5FFC9C8 + C8FFBEBDBDFF9F9F9FFF484646FF484646FF979696FF626262FF000000006161 + 61FFA5A4A4FF3E3C3CFF3D3B3BFF3C3A3AFF3C3A3AFF3E3C3CFF3F3D3DFF3E3B + 3BFF3E3C3CFF413F3FFF444242FF423F3FFFA5A4A4FF616161FF000000006161 + 61FFB5B4B3FF8D8B8AFF8F8C8CFF8F8C8CFF8F8C8CFF8F8D8CFF8F8D8CFF8F8D + 8CFF8F8D8CFF908D8DFF908D8DFF8E8B8BFFB5B4B3FF616161FF000000004341 + 40AA625F5CFF625F5CFF635F5DFF63605DFF63605DFF63605DFF63605DFF6360 + 5DFF63605DFF63605DFF635F5DFF625F5CFF625F5CFF535150D4000000000000 + 0000509CD3FF00000000509CD3FF00000000509CD3FF00000000509CD3FF0000 + 0000509CD3FF00000000509CD3FF00000000509CD3FF00000000000000000000 + 00005397C8FF000000005397C7FF000000005397C7FF000000005397C7FF0000 + 00005397C7FF000000005397C7FF000000005397C8FF00000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end> + end +end diff --git a/assets/InstructionEditor/Forms/Editors/formEditorX86Registers.pas b/assets/InstructionEditor/Forms/Editors/formEditorX86Registers.pas new file mode 100644 index 0000000..5df9297 --- /dev/null +++ b/assets/InstructionEditor/Forms/Editors/formEditorX86Registers.pas @@ -0,0 +1,263 @@ +unit formEditorX86Registers; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, untInstructionEditor, System.ImageList, Vcl.ImgList, + cxGraphics, Vcl.StdCtrls, VirtualTrees; + +type + TfrmEditorX86Registers = class(TForm) + GroupBox: TGroupBox; + btnCancel: TButton; + btnApply: TButton; + imgIcons16: TcxImageList; + VirtualTreeView: TVirtualStringTree; + imgTreeView: TcxImageList; + procedure btnApplyClick(Sender: TObject); + procedure btnCancelClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure VirtualTreeViewFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure VirtualTreeViewGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure VirtualTreeViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure VirtualTreeViewCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; + var Allowed: Boolean); + procedure VirtualTreeViewChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); + strict private + FApplyChanges: Boolean; + FRegisters: TX86RegisterSet; + strict private + procedure SetRegisters(const Value: TX86RegisterSet); + public + property ApplyChanges: Boolean read FApplyChanges; + property Registers: TX86RegisterSet read FRegisters write SetRegisters; + end; + +var + frmEditorX86Registers: TfrmEditorX86Registers; + +implementation + +uses + System.TypInfo; + +{$R *.dfm} + +type + PNodeData = ^TNodeData; + TNodeData = record + public + IsCategory: Boolean; + Text: String; + Value: TX86Register; + end; + +{ TfrmEditorX86Registers } + +procedure TfrmEditorX86Registers.btnApplyClick(Sender: TObject); +begin + FApplyChanges := true; + Close; +end; + +procedure TfrmEditorX86Registers.btnCancelClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmEditorX86Registers.FormCreate(Sender: TObject); + +function AddCategory(Root: PVirtualNode; const Text: String): PVirtualNode; +var + NodeData: PNodeData; +begin + Result := VirtualTreeView.AddChild(Root); + if (Assigned(Root)) then + begin + VirtualTreeView.CheckType[Result] := ctTriStateCheckBox; + end; + NodeData := VirtualTreeView.GetNodeData(Result); + NodeData^.IsCategory := true; + NodeData^.Text := Text; +end; + +procedure AddRegisterRange(Root: PVirtualNode; RegisterLow, RegisterHigh: TX86Register); +var + Node: PVirtualNode; + NodeData: PNodeData; + R: TX86Register; + S: String; +begin + for R := RegisterLow to RegisterHigh do + begin + Node := VirtualTreeView.AddChild(Root); + VirtualTreeView.CheckType[Node] := ctTriStateCheckBox; + NodeData := VirtualTreeView.GetNodeData(Node); + NodeData^.IsCategory := false; + S := GetEnumName(TypeInfo(TX86Register), Ord(R)); + Delete(S, 1, 3); + NodeData^.Text := S; + NodeData^.Value := R; + end; +end; + +var + Root, N1, N2: PVirtualNode; +begin + FRegisters := []; + VirtualTreeView.NodeDataSize := SizeOf(TNodeData); + VirtualTreeView.BeginUpdate; + try + Root := AddCategory(nil, 'Root'); + + N1 := AddCategory(Root, 'General Purpose Registers'); + N2 := AddCategory(N1, '64-bit'); + AddRegisterRange(N2, regRAX, regR15); + N2 := AddCategory(N1, '32-bit'); + AddRegisterRange(N2, regEAX, regR15D); + N2 := AddCategory(N1, '16-bit'); + AddRegisterRange(N2, regAX, regR15W); + N2 := AddCategory(N1, '8-bit'); + AddRegisterRange(N2, regAL, regR15B); + VirtualTreeView.Expanded[N1] := true; + + N1 := AddCategory(Root, 'Floating Point Registers'); + N2 := AddCategory(N1, 'Legacy'); + AddRegisterRange(N2, regST0, regST7); + N2 := AddCategory(N1, 'Multimedia'); + AddRegisterRange(N2, regMM0, regMM7); + VirtualTreeView.Expanded[N1] := true; + + N1 := AddCategory(Root, 'Vector Registers'); + N2 := AddCategory(N1, '512-bit'); + AddRegisterRange(N2, regZMM0, regZMM31); + N2 := AddCategory(N1, '256-bit'); + AddRegisterRange(N2, regYMM0, regYMM31); + N2 := AddCategory(N1, '128-bit'); + AddRegisterRange(N2, regXMM0, regXMM31); + VirtualTreeView.Expanded[N1] := true; + + N1 := AddCategory(Root, 'Special Registers'); + AddRegisterRange(N1, regRFLAGS, regIP); + + N1 := AddCategory(Root, 'Segment Registers'); + AddRegisterRange(N1, regES, regFS); + + N1 := AddCategory(Root, 'Control Registers'); + AddRegisterRange(N1, regCR0, regCR15); + + N1 := AddCategory(Root, 'Debug Registers'); + AddRegisterRange(N1, regDR0, regDR15); + + N1 := AddCategory(Root, 'Mask Registers'); + AddRegisterRange(N1, regK0, regK7); + + N1 := AddCategory(Root, 'Bound Registers'); + AddRegisterRange(N1, regBND0, regBND3); + + VirtualTreeView.Expanded[Root] := true; + finally + VirtualTreeView.EndUpdate; + end; +end; + +procedure TfrmEditorX86Registers.VirtualTreeViewChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + NodeData: PNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData) and (not NodeData^.IsCategory)) then + begin + case Sender.CheckState[Node] of + csCheckedNormal: + FRegisters := FRegisters + [NodeData^.Value]; + csUncheckedNormal: + FRegisters := FRegisters - [NodeData^.Value]; + end; + end; +end; + +procedure TfrmEditorX86Registers.VirtualTreeViewCollapsing(Sender: TBaseVirtualTree; + Node: PVirtualNode; var Allowed: Boolean); +begin + Allowed := (Node.Parent <> Sender.RootNode); +end; + +procedure TfrmEditorX86Registers.VirtualTreeViewFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + NodeData: PNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + Finalize(NodeData^); + end; +end; + +procedure TfrmEditorX86Registers.VirtualTreeViewGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; + var ImageIndex: Integer); +var + NodeData: PNodeData; +begin + ImageIndex := -1; + if (Kind in [ikNormal, ikSelected]) then + begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + if (NodeData^.IsCategory) then + begin + ImageIndex := 0; + end else + begin + ImageIndex := 1; + end; + end; + end; +end; + +procedure TfrmEditorX86Registers.VirtualTreeViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + NodeData: PNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + CellText := NodeData^.Text; + end; +end; + +procedure TfrmEditorX86Registers.SetRegisters(const Value: TX86RegisterSet); +var + Node: PVirtualNode; + NodeData: PNodeData; +begin + VirtualTreeView.BeginUpdate; + try + Node := VirtualTreeView.GetFirst; + while (Assigned(Node)) do + begin + NodeData := VirtualTreeView.GetNodeData(Node); + if (Assigned(NodeData) and (not NodeData^.IsCategory)) then + begin + if (NodeData^.Value in Value) then + begin + VirtualTreeView.CheckState[Node] := csCheckedNormal; + end else + begin + VirtualTreeView.CheckState[Node] := csUncheckedNormal; + end; + end; + Node := VirtualTreeView.GetNext(Node); + end; + finally + VirtualTreeView.EndUpdate; + end; +end; + +end. diff --git a/assets/InstructionEditor/Forms/formCreateDefinition.dfm b/assets/InstructionEditor/Forms/formCreateDefinition.dfm new file mode 100644 index 0000000..d2fc7c0 --- /dev/null +++ b/assets/InstructionEditor/Forms/formCreateDefinition.dfm @@ -0,0 +1,157 @@ +object frmCreateDefinition: TfrmCreateDefinition + Left = 0 + Top = 0 + BorderStyle = bsDialog + Caption = 'Create Definition' + ClientHeight = 446 + ClientWidth = 644 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object GroupBox: TGroupBox + AlignWithMargins = True + Left = 3 + Top = 404 + Width = 638 + Height = 39 + Margins.Top = 0 + Align = alBottom + TabOrder = 1 + DesignSize = ( + 638 + 39) + object btnCancel: TButton + Left = 518 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Cancel' + ImageIndex = 1 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 1 + OnClick = btnCancelClick + end + object btnApply: TButton + Left = 400 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Ok' + ImageIndex = 0 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 0 + OnClick = btnApplyClick + end + end + object Inspector: TcxRTTIInspector + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 638 + Height = 398 + Align = alClient + Constraints.MinWidth = 350 + InspectedObject = Owner + LookAndFeel.NativeStyle = True + OptionsView.PaintStyle = psdotNet + OptionsView.RowHeaderMinWidth = 120 + OptionsView.RowHeaderWidth = 260 + OptionsView.ShowReadOnlyProperties = True + OptionsView.Sorted = False + TabOrder = 0 + Version = 1 + end + object imgIcons16: TcxImageList + FormatVersion = 1 + DesignInfo = 2097208 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 20000000000000040000000000000000000000000000000000000000001B0000 + 0033000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000001B00000000004B29A00089 + 49FF008747FF008747FF008747FF008747FF008747FF008747FF008747FF0087 + 47FF008747FF008747FF008747FF008949FF004B29A000000000008949FF07E4 + A4FF07E5A5FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4 + A4FF07E4A4FF07E4A4FF07E5A5FF07E4A4FF008949FF00000000008747FF13E7 + AAFF00DB9BFF00DA9AFF00DA99FF00DA99FF00DA99FF00DA99FF00DA9AFF00DA + 9AFF00DA9AFF00DA9AFF00DB9BFF13E7AAFF008747FF00000000008746FF1EE7 + AEFF00D699FF00D698FF00D495FF00D391FF00D391FF00D495FF00D698FF00D6 + 99FF00D699FF00D699FF00D699FF1EE7AEFF008746FF00000000008746FF2AE9 + B3FF00D299FF00D095FF00CC8DFFFFFFFFFFFFFFFFFF00CC8DFF00D096FF00D2 + 99FF00D29AFF00D29AFF00D29AFF2AE9B3FF008746FF00000000008746FF35EA + B7FF00CD96FF00C98DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C98DFF00CD + 96FF00CF99FF00CF9AFF00CF9AFF36EAB8FF008746FF00000000008745FF3EEB + BBFF00C692FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C4 + 8DFF00C995FF00CA99FF00CA99FF41ECBDFF008745FF00000000008745FF4BED + BFFF00C393FFFFFFFFFFFFFFFFFF00C08BFF00BF8BFFFFFFFFFFFFFFFFFFFFFF + FFFF00C18EFF00C596FF00C699FF4DEDC0FF008745FF00000000008744FF58EF + C5FF00C197FF00BF93FF00C093FF00C196FF00C196FF00BC8EFFFFFFFFFFFFFF + FFFFFFFFFFFF00BC8EFF00C096FF58EFC5FF008744FF00000000008744FF64F1 + CAFF00BE99FF00C099FF00C09AFF00C19BFF00C19AFF00BE97FF00B98EFFFFFF + FFFFFFFFFFFFFFFFFFFF00BA92FF62F0C9FF008744FF00000000008744FF71F2 + CFFF00BB99FF00BD9AFF00BE9BFF00BE9BFF00BE9BFF00BE9AFF00BB96FF00B6 + 8EFFFFFFFFFFFFFFFFFF00B792FF6EF2CDFF008744FF00000000008744FF7BF4 + D3FF00B699FF00B89AFF00B99BFF00B99BFF00B99BFF00B99BFF00B89AFF00B7 + 98FF00B494FF00B493FF00B496FF7AF3D3FF008744FF00000000008744FF86F5 + D8FF00B198FF00B299FF00B399FF00B399FF00B399FF00B399FF00B399FF00B2 + 99FF00B298FF00B297FF00B197FF86F5D8FF008744FF00000000008946FF8AF2 + D9FF92F6DEFF93F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6 + DDFF94F6DDFF93F6DDFF92F6DEFF8AF2D9FF008946FF00000000004B29880089 + 46FF008743FF008643FF008643FF008643FF008643FF008643FF008643FF0086 + 43FF008643FF008643FF008743FF008946FF004B298800000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0013000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000003300000013000000001117 + 487E2D3CC0FF2B3BBEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3A + BEFF2A3ABEFF2A3ABEFF2A3ABEFF2B3BBEFF2D3CC0FF1117487E000000002D3D + C0FF6172FAFF6A7DFFFF697CFFFF6D80FFFF7485FFFF7788FFFF7788FFFF7788 + FFFF7485FFFF6D7FFFFF697CFFFF6A7DFFFF6172FAFF2D3DC0FF000000002B3B + BEFF6578FFFF5F73FEFF6F80FFFF7989FFFF5868E6FF3E4ED0FF3F4FD1FF3E4E + D0FF5767E5FF7887FEFF6E7FFFFF5F73FEFF6578FFFF2B3BBEFF000000002B3B + BEFF5D72FFFF697BFEFF7785F8FF3949CAFF1E2A89B70B0F303F07091D26070A + 1F552636B9FF5A6FFDFF576CFAFF687AFCFF5D71FFFF2B3BBEFF000000002C3B + BFFF586EFEFF8593FFFF3B4BCAFF0E143F530000000000000000000000332B3A + BDFF5970FEFF546AFBFF7F8FFFFF8290FDFF586EFEFF2C3BBFFF000000002C3C + BFFF536BFCFF707CE7FF1E2A89BB0000000000000000000000332C3BBEFF546B + FBFF5067F8FF8796FFFF3B4BCDFF6D79E5FF536AFCFF2C3CBFFF000000002D3D + BFFF4F68FBFF4E5BD1FF0B0F304500000000000000332C3BBEFF4E66F9FF4A63 + F6FF8C99FFFF2737BCFF07091F314D5AD0FF4F68FBFF2D3DBFFF000000002E3D + C0FF4A64F9FF3446CDFF07091D2D000000332D3CBEFF4862F7FF445DF4FF8E9C + FFFF2838BDFF0000000007091D313446CDFF4A64F9FF2E3DC0FF000000002E3D + C0FF4660F7FF3445CCFF080A20552D3CBEFF445DF4FF3F59F1FF929FFFFF2838 + BDFF00000000000000000C0F305B3445CDFF4660F7FF2E3DC0FF000000002E3E + C0FF405BF3FF384DDBFF2E3CBCFF3E59F2FF3954EFFF95A2FFFF2838BDFF0000 + 00000000000000000011222D8AC5384EDCFF405BF3FF2E3EC0FF000000002F3E + C0FF3955F0FF3951EAFF3954EEFF3651EDFF9AA5FFFF2838BDFF000000080000 + 000D0000002510153F753041C8FF3A53EBFF3A55F0FF2F3EC0FF000000002E3D + BFFF3A54EFFF324DE9FF334DE9FF324DEBFF2A39BCFF070A1F5507091D510B0F + 3065212D8AC52F41C8FF314CE4FF324DEBFF3A54EFFF2E3DBFFF000000002B3B + BFFF6A7DFDFF334EE8FF2643E4FF2642E3FF253CD4FF2739C7FF273AC8FF273A + C8FF263DD5FF2743E5FF2643E6FF334EE9FF6A7DFDFF2B3BBFFF000000002B3B + C0FF929DFCFFAAB3FFFFAAB3FFFFAAB3FFFFAAB4FFFFAAB4FFFFAAB4FFFFAAB4 + FFFFAAB4FFFFAAB3FFFFAAB3FFFFAAB3FFFF929DFCFF2B3BC0FF000000001117 + 485E2A3AC0FF2838BFFF2737BEFF2737BEFF2737BEFF2737BFFF2737BFFF2737 + BFFF2737BEFF2737BEFF2737BEFF2838BFFF2A3AC0FF1117485E} + end> + end +end diff --git a/assets/InstructionEditor/Forms/formCreateDefinition.pas b/assets/InstructionEditor/Forms/formCreateDefinition.pas new file mode 100644 index 0000000..8db6b3b --- /dev/null +++ b/assets/InstructionEditor/Forms/formCreateDefinition.pas @@ -0,0 +1,50 @@ +unit formCreateDefinition; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, cxGraphics, cxControls, cxLookAndFeels, + cxLookAndFeelPainters, cxStyles, cxEdit, dxSkinsCore, cxInplaceContainer, cxVGrid, cxOI, + System.ImageList, Vcl.ImgList, Vcl.StdCtrls, dxSkinSeven; + +type + TfrmCreateDefinition = class(TForm) + GroupBox: TGroupBox; + btnCancel: TButton; + btnApply: TButton; + imgIcons16: TcxImageList; + Inspector: TcxRTTIInspector; + procedure btnCancelClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure btnApplyClick(Sender: TObject); + private + FCanceled: Boolean; + public + property Canceled: Boolean read FCanceled; + end; + +var + frmCreateDefinition: TfrmCreateDefinition; + +implementation + +{$R *.dfm} + +procedure TfrmCreateDefinition.btnApplyClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmCreateDefinition.btnCancelClick(Sender: TObject); +begin + FCanceled := true; + Close; +end; + +procedure TfrmCreateDefinition.FormCreate(Sender: TObject); +begin + FCanceled := false; +end; + +end. diff --git a/assets/InstructionEditor/Forms/formGenerator.dfm b/assets/InstructionEditor/Forms/formGenerator.dfm new file mode 100644 index 0000000..fc03640 --- /dev/null +++ b/assets/InstructionEditor/Forms/formGenerator.dfm @@ -0,0 +1,329 @@ +object frmGenerator: TfrmGenerator + Left = 0 + Top = 0 + BorderStyle = bsDialog + Caption = 'Generator' + ClientHeight = 371 + ClientWidth = 544 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object GroupBox: TGroupBox + AlignWithMargins = True + Left = 3 + Top = 329 + Width = 538 + Height = 39 + Margins.Top = 0 + Align = alBottom + TabOrder = 0 + DesignSize = ( + 538 + 39) + object btnClose: TButton + Left = 418 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Close' + ImageIndex = 1 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 1 + OnClick = btnCloseClick + end + object btnGenerate: TButton + Left = 300 + Top = 7 + Width = 112 + Height = 25 + Anchors = [akTop, akRight] + Caption = 'Generate' + ImageIndex = 0 + ImageMargins.Left = 2 + ImageMargins.Top = 2 + Images = imgIcons16 + TabOrder = 0 + OnClick = btnGenerateClick + end + end + object TreeView: TVirtualStringTree + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 538 + Height = 323 + Align = alClient + Header.AutoSizeIndex = 0 + Header.Font.Charset = DEFAULT_CHARSET + Header.Font.Color = clWindowText + Header.Font.Height = -11 + Header.Font.Name = 'Tahoma' + Header.Font.Style = [] + Header.Options = [hoAutoResize, hoVisible] + Images = imgTreeView + TabOrder = 1 + TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toAlwaysHideSelection, toUseBlendedSelection] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnBeforeCellPaint = TreeViewBeforeCellPaint + OnCollapsing = TreeViewCollapsing + OnFreeNode = TreeViewFreeNode + OnGetText = TreeViewGetText + OnGetImageIndex = TreeViewGetImageIndex + Columns = < + item + Position = 0 + Width = 384 + WideText = 'Name' + end + item + Alignment = taRightJustify + Position = 1 + Width = 150 + WideText = 'Value' + end> + end + object imgIcons16: TcxImageList + FormatVersion = 1 + DesignInfo = 2097208 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 20000000000000040000000000000000000000000000000000000000001B0000 + 0033000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000001B00000000004B29A00089 + 49FF008747FF008747FF008747FF008747FF008747FF008747FF008747FF0087 + 47FF008747FF008747FF008747FF008949FF004B29A000000000008949FF07E4 + A4FF07E5A5FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4A4FF07E4 + A4FF07E4A4FF07E4A4FF07E5A5FF07E4A4FF008949FF00000000008747FF13E7 + AAFF00DB9BFF00DA9AFF00DA99FF00DA99FF00DA99FF00DA99FF00DA9AFF00DA + 9AFF00DA9AFF00DA9AFF00DB9BFF13E7AAFF008747FF00000000008746FF1EE7 + AEFF00D699FF00D698FF00D495FF00D391FF00D391FF00D495FF00D698FF00D6 + 99FF00D699FF00D699FF00D699FF1EE7AEFF008746FF00000000008746FF2AE9 + B3FF00D299FF00D095FF00CC8DFFFFFFFFFFFFFFFFFF00CC8DFF00D096FF00D2 + 99FF00D29AFF00D29AFF00D29AFF2AE9B3FF008746FF00000000008746FF35EA + B7FF00CD96FF00C98DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C98DFF00CD + 96FF00CF99FF00CF9AFF00CF9AFF36EAB8FF008746FF00000000008745FF3EEB + BBFF00C692FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00C4 + 8DFF00C995FF00CA99FF00CA99FF41ECBDFF008745FF00000000008745FF4BED + BFFF00C393FFFFFFFFFFFFFFFFFF00C08BFF00BF8BFFFFFFFFFFFFFFFFFFFFFF + FFFF00C18EFF00C596FF00C699FF4DEDC0FF008745FF00000000008744FF58EF + C5FF00C197FF00BF93FF00C093FF00C196FF00C196FF00BC8EFFFFFFFFFFFFFF + FFFFFFFFFFFF00BC8EFF00C096FF58EFC5FF008744FF00000000008744FF64F1 + CAFF00BE99FF00C099FF00C09AFF00C19BFF00C19AFF00BE97FF00B98EFFFFFF + FFFFFFFFFFFFFFFFFFFF00BA92FF62F0C9FF008744FF00000000008744FF71F2 + CFFF00BB99FF00BD9AFF00BE9BFF00BE9BFF00BE9BFF00BE9AFF00BB96FF00B6 + 8EFFFFFFFFFFFFFFFFFF00B792FF6EF2CDFF008744FF00000000008744FF7BF4 + D3FF00B699FF00B89AFF00B99BFF00B99BFF00B99BFF00B99BFF00B89AFF00B7 + 98FF00B494FF00B493FF00B496FF7AF3D3FF008744FF00000000008744FF86F5 + D8FF00B198FF00B299FF00B399FF00B399FF00B399FF00B399FF00B399FF00B2 + 99FF00B298FF00B297FF00B197FF86F5D8FF008744FF00000000008946FF8AF2 + D9FF92F6DEFF93F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6DDFF94F6 + DDFF94F6DDFF93F6DDFF92F6DEFF8AF2D9FF008946FF00000000004B29880089 + 46FF008743FF008643FF008643FF008643FF008643FF008643FF008643FF0086 + 43FF008643FF008643FF008743FF008946FF004B298800000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0013000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000330000003300000013000000001117 + 487E2D3CC0FF2B3BBEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3ABEFF2A3A + BEFF2A3ABEFF2A3ABEFF2A3ABEFF2B3BBEFF2D3CC0FF1117487E000000002D3D + C0FF6172FAFF6A7DFFFF697CFFFF6D80FFFF7485FFFF7788FFFF7788FFFF7788 + FFFF7485FFFF6D7FFFFF697CFFFF6A7DFFFF6172FAFF2D3DC0FF000000002B3B + BEFF6578FFFF5F73FEFF6F80FFFF7989FFFF5868E6FF3E4ED0FF3F4FD1FF3E4E + D0FF5767E5FF7887FEFF6E7FFFFF5F73FEFF6578FFFF2B3BBEFF000000002B3B + BEFF5D72FFFF697BFEFF7785F8FF3949CAFF1E2A89B70B0F303F07091D26070A + 1F552636B9FF5A6FFDFF576CFAFF687AFCFF5D71FFFF2B3BBEFF000000002C3B + BFFF586EFEFF8593FFFF3B4BCAFF0E143F530000000000000000000000332B3A + BDFF5970FEFF546AFBFF7F8FFFFF8290FDFF586EFEFF2C3BBFFF000000002C3C + BFFF536BFCFF707CE7FF1E2A89BB0000000000000000000000332C3BBEFF546B + FBFF5067F8FF8796FFFF3B4BCDFF6D79E5FF536AFCFF2C3CBFFF000000002D3D + BFFF4F68FBFF4E5BD1FF0B0F304500000000000000332C3BBEFF4E66F9FF4A63 + F6FF8C99FFFF2737BCFF07091F314D5AD0FF4F68FBFF2D3DBFFF000000002E3D + C0FF4A64F9FF3446CDFF07091D2D000000332D3CBEFF4862F7FF445DF4FF8E9C + FFFF2838BDFF0000000007091D313446CDFF4A64F9FF2E3DC0FF000000002E3D + C0FF4660F7FF3445CCFF080A20552D3CBEFF445DF4FF3F59F1FF929FFFFF2838 + BDFF00000000000000000C0F305B3445CDFF4660F7FF2E3DC0FF000000002E3E + C0FF405BF3FF384DDBFF2E3CBCFF3E59F2FF3954EFFF95A2FFFF2838BDFF0000 + 00000000000000000011222D8AC5384EDCFF405BF3FF2E3EC0FF000000002F3E + C0FF3955F0FF3951EAFF3954EEFF3651EDFF9AA5FFFF2838BDFF000000080000 + 000D0000002510153F753041C8FF3A53EBFF3A55F0FF2F3EC0FF000000002E3D + BFFF3A54EFFF324DE9FF334DE9FF324DEBFF2A39BCFF070A1F5507091D510B0F + 3065212D8AC52F41C8FF314CE4FF324DEBFF3A54EFFF2E3DBFFF000000002B3B + BFFF6A7DFDFF334EE8FF2643E4FF2642E3FF253CD4FF2739C7FF273AC8FF273A + C8FF263DD5FF2743E5FF2643E6FF334EE9FF6A7DFDFF2B3BBFFF000000002B3B + C0FF929DFCFFAAB3FFFFAAB3FFFFAAB3FFFFAAB4FFFFAAB4FFFFAAB4FFFFAAB4 + FFFFAAB4FFFFAAB3FFFFAAB3FFFFAAB3FFFF929DFCFF2B3BC0FF000000001117 + 485E2A3AC0FF2838BFFF2737BEFF2737BEFF2737BEFF2737BFFF2737BFFF2737 + BFFF2737BEFF2737BEFF2737BEFF2838BFFF2A3AC0FF1117485E} + end> + end + object imgTreeView: TcxImageList + FormatVersion = 1 + DesignInfo = 2097288 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000300000 + 0033000000330000003300000033000000330000003300000033000000330000 + 00330000003300000033000000330000002F00000000000000004190C6F24398 + D2FF4094D0FF3E92CFFF3E92CEFF3F92CEFF3F92CEFF3F92CEFF3F92CEFF3F92 + CEFF3F92CEFF3F92CEFF3F93CFFF3D8BC2F00000000E000000004499D2FF3F94 + D0FFABFBFFFF9BF3FFFF92F1FFFF93F1FFFF93F1FFFF93F1FFFF93F1FFFF93F1 + FFFF93F1FFFF93F1FFFFA6F8FFFF65B8E3FF122A3A5F000000004398D2FF4FA6 + D9FF8EDAF5FFA2EEFFFF82E5FEFF84E5FEFF84E5FEFF85E6FEFF85E6FEFF85E6 + FEFF85E6FEFF84E6FEFF96EBFFFF8CD8F5FF296088B8000000004296D1FF6BBE + E8FF6DBDE6FFBBF2FFFF75DEFDFF77DEFCFF78DEFCFF7BDFFCFF7DDFFCFF7DDF + FCFF7DDFFCFF7CDFFCFF80E0FDFFADF0FFFF4D9DD3FF0000000E4095D0FF8AD7 + F5FF44A1D8FFDDFDFFFFDAFAFFFFDBFAFFFFDEFAFFFF74DCFCFF76DBFAFF75DA + FAFF74DAFAFF74DAFAFF72D9FAFFA1E8FFFF7CBFE6FF12293A5E3E94D0FFABF0 + FFFF449DD6FF368CCBFF368CCBFF368CCBFF378BCBFF5CBEEAFF6FD9FBFF6AD6 + FAFF68D5F9FF67D4F9FF66D4F9FF82DEFCFFAAE0F6FF296088B93D92CFFFB9F4 + FFFF73DBFBFF6BCCF2FF6CCDF3FF6CCEF3FF6DCEF3FF479CD4FF56BAE9FFDAF8 + FFFFD7F6FFFFD6F6FFFFD5F6FFFFD5F7FFFFDBFCFFFF3E94D0FF3C92CFFFC0F3 + FFFF71DAFBFF74DBFBFF75DBFCFF75DBFCFF76DCFCFF73DAFAFF449CD4FF378C + CBFF368CCBFF358CCCFF348DCCFF3890CEFF3D94D0FF3E8CC2EB3B92CFFFCAF6 + FFFF69D5F9FF6CD5F9FF6BD5F9FF69D5F9FF69D5FAFF6AD7FBFF68D4FAFF5EC7 + F1FF5EC7F2FF5DC8F2FFB4E3F8FF3D94D0FF1A3B5269000000003B92CFFFD5F7 + FFFF60D1F9FF61D0F8FFB4EBFDFFD9F6FFFFDAF8FFFFDAF8FFFFDBF9FFFFDCFA + FFFFDCFAFFFFDCFBFFFFE0FFFFFF3E95D0FF0E1F2A33000000003D94D0FFDCFC + FFFFD8F7FFFFD8F7FFFFDBFAFFFF358ECDFF3991CEFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3B92CFFF3D94D0FF3880B1D700000000000000002E6991B03D94 + D0FF3A92CFFF3A92CFFF3D94D0FF367CACD20000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000001E00000033000000330000 + 00330000001E0000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000001E3B3B3BAC636363FF626263FF6363 + 63FF3B3B3BAC0000001E00000000000000000000000000000000000000000000 + 00000000000000000000000000003B3B3BAC6F6E6EFF95918FFF989492FF9591 + 8FFF6F6E6EFF3B3B3BAC00000000000000000000000000000000000000000000 + 0000000000000000000000000000636464FF858381FF878481FF868381FF8784 + 81FF858381FF636464FF00000000000000000000000000000000000000000000 + 0000000000000000000000000000626363FF8E8C8BFF767371FF767371FF7673 + 71FF8E8C8BFF626363FF00000000000000000000000000000000000000000000 + 0000000000000000000000000000626363FFA7A5A5FF7D7B7AFF787675FF7D7B + 7AFFA7A5A5FF626363FF00000000000000000000000000000000000000000000 + 00000000000000000000000000003B3B3B976F6E6EFFA6A5A4FFA9A8A9FFA6A5 + A4FF6D6E6EFF3B3B3B9700000000000000000000000000000000000000000000 + 0000000000000000000000000000000000003B3B3B97626262FF616161FF6262 + 62FF3B3B3B970000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000024000000330000 + 002F000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000005F31C100C684FF007D + 41ED000000290000000000000000000000000000000000000000000000000000 + 00000000000000000024000000330000003300000033008847FF00E4A6FF00BE + 80FF006F3BD90000002100000000000000000000000000000000000000000000 + 000000000000005F31C1008A48FF008847FF008746FF008847FF00D9A1FF00D8 + A0FF00BC80FF005A2FB900000022000000000000000000000000000000000000 + 000000000000008947FF43E8C2FF00D7A0FF00D7A0FF00D59FFF00D09CFF00D0 + 9CFF00D39FFF00B981FF005D32BD000000000000000000000000000000000000 + 000000000000008845FF6FE8D0FF00C899FF00C899FF00C899FF00C797FF00C8 + 98FF00CA9AFF63E6CDFF008A47FF000000000000000000000000000000000000 + 000000000000008946FF99F0E4FF4FE9D5FF51E8D4FF4DE6D1FF94E8D8FF00C3 + 97FF60E0C7FF00B281FF005E31AC000000000000000000000000000000000000 + 000000000000005F32B2008946FF008744FF008642FF008847FF82E4D6FF5ADA + C4FF00AD7FFF005A2EA700000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000008847FF7AE4D8FF00AA + 7FFF006F39CF0000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000005F32B200AA85FF007E + 40E9000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000001E00000033000000330000 + 00330000001E0000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000001E6E4F11ACB78319FFB68218FFB783 + 19FF6E4F11AC0000001E00000000000000000000000000000000000000000000 + 00000000000000000000000000006E4F11ACC5922FFFEDC074FFF1C47AFFEDC0 + 74FFC5922FFF6E4F11AC00000000000000000000000000000000000000000000 + 0000000000000000000000000000B7841AFFEAB45CFFE9B45CFFE8B35BFFE9B4 + 5CFFEAB45CFFB7841AFF00000000000000000000000000000000000000000000 + 0000000000000000000000000000B78219FFEBB964FFE3A641FFE3A641FFE3A6 + 41FFEBB964FFB78219FF00000000000000000000000000000000000000000000 + 0000000000000000000000000000B78319FFEEC684FFE5AA49FFE2A641FFE5AA + 49FFEEC684FFB78319FF00000000000000000000000000000000000000000000 + 00000000000000000000000000006E4F1197C6922EFFECC482FFEFC886FFECC4 + 82FFC6912CFF6E4F119700000000000000000000000000000000000000000000 + 0000000000000000000000000000000000006E4F1197B78319FFB68217FFB783 + 19FF6E4F11970000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end> + end +end diff --git a/assets/InstructionEditor/Forms/formGenerator.pas b/assets/InstructionEditor/Forms/formGenerator.pas new file mode 100644 index 0000000..5f35205 --- /dev/null +++ b/assets/InstructionEditor/Forms/formGenerator.pas @@ -0,0 +1,395 @@ +unit formGenerator; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, System.ImageList, Vcl.ImgList, cxGraphics, + Vcl.StdCtrls, untInstructionEditor; + +type + TfrmGenerator = class(TForm) + GroupBox: TGroupBox; + btnClose: TButton; + btnGenerate: TButton; + imgIcons16: TcxImageList; + TreeView: TVirtualStringTree; + imgTreeView: TcxImageList; + procedure FormCreate(Sender: TObject); + procedure TreeViewCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; + var Allowed: Boolean); + procedure TreeViewFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure TreeViewGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure TreeViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); + procedure btnCloseClick(Sender: TObject); + procedure btnGenerateClick(Sender: TObject); + procedure TreeViewBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); + strict private + FEditor: TInstructionEditor; + FProgressNodeTotal: PVirtualNode; + FProgressNode: array[TGeneratorWorkOperation] of PVirtualNode; + FInfoNode: array[0..6] of PVirtualNode; + FCurrentOperation: TGeneratorWorkOperation; + strict private + procedure GeneratorWorkStart(Sender: TObject; Operation: TGeneratorWorkOperation; MinWorkCount, + MaxWorkCount: Integer); + procedure GeneratorWork(Sender: TObject; WorkCount: Integer); + procedure GeneratorWorkEnd(Sender: TObject); + public + property Editor: TInstructionEditor read FEditor write FEditor; + end; + +var + frmGenerator: TfrmGenerator; + +implementation + +uses + untHelperClasses; + +{$R *.dfm} + +type + TGeneratorNodeType = (ntCategory, ntSpacer, ntOperation, ntValue); + + PGeneratorNodeData = ^TGeneratorNodeData; + TGeneratorNodeData = record + public + NodeType: TGeneratorNodeType; + Text: String; + ProgressActive: Boolean; + ProgressMax: Integer; + ProgressUpdateStep: Integer; + Progress: Double; + Value: String; + public + procedure ProgressInit(MaxWorkCount: Integer; MinWorkCount: Integer); inline; + procedure ProgressUpdate(NewProgress: Double); inline; + procedure WorkCountUpdate(WorkCount: Integer); inline; + function IsProgressUpdateStep(WorkCount: Integer): Boolean; inline; + end; + +{ TGeneratorNodeData } + +function TGeneratorNodeData.IsProgressUpdateStep(WorkCount: Integer): Boolean; +begin + Assert(NodeType = ntOperation); + Result := ((WorkCount mod ProgressUpdateStep) = 0); +end; + +procedure TGeneratorNodeData.ProgressInit(MaxWorkCount, MinWorkCount: Integer); +begin + Assert(NodeType = ntOperation); + ProgressMax := (MaxWorkCount - MinWorkCount); + ProgressUpdateStep := Round(ProgressMax / 100) + 1; +end; + +procedure TGeneratorNodeData.ProgressUpdate(NewProgress: Double); +var + Format: TFormatSettings; +begin + Assert(NodeType = ntOperation); + Progress := NewProgress; + Format.DecimalSeparator := '.'; + Value := FormatFloat('0.00', Progress * 100, Format) + '%'; +end; + +procedure TGeneratorNodeData.WorkCountUpdate(WorkCount: Integer); +begin + Assert(NodeType = ntOperation); + if (ProgressMax = 0) then + begin + ProgressUpdate(1.0); + end else + begin + ProgressUpdate(WorkCount / ProgressMax); + end; +end; + +{ TfrmGenerator } + +procedure TfrmGenerator.btnCloseClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmGenerator.btnGenerateClick(Sender: TObject); + +procedure SetInfoNodeValue(Node: PVirtualNode; const Value: String); +var + NodeData: PGeneratorNodeData; +begin + NodeData := TreeView.GetNodeData(Node); + NodeData^.Value := Value; +end; + +var + Generator: TTableGenerator; + Node: PVirtualNode; + NodeData: PGeneratorNodeData; + I: Integer; +begin + TreeView.BeginUpdate; + try + for Node in FProgressNode do + begin + NodeData := TreeView.GetNodeData(Node); + NodeData^.ProgressActive := false; + NodeData^.ProgressUpdate(0); + end; + NodeData := TreeView.GetNodeData(FProgressNodeTotal); + NodeData^.ProgressActive := false; + NodeData^.ProgressUpdate(0); + finally + TreeView.EndUpdate; + end; + Generator := TTableGenerator.Create; + try + Generator.OnWorkStart := GeneratorWorkStart; + Generator.OnWork := GeneratorWork; + Generator.OnWorkEnd := GeneratorWorkEnd; + Generator.GenerateFiles(FEditor, + 'D:\Verteron Development\GitHub\zyan-disassembler-engine old\include\Zydis\Internal\'); + TreeView.BeginUpdate; + try + for I := Low(FInfoNode) to High(FInfoNode) do + begin + case I of + 0: SetInfoNodeValue(FInfoNode[I], IntToStr(Generator.Statistics.FilterCount)); + 1: SetInfoNodeValue(FInfoNode[I], IntToStr(Generator.Statistics.DefinitionCount)); + 2: SetInfoNodeValue(FInfoNode[I], IntToStr(Generator.Statistics.MnemonicCount)); + 3: SetInfoNodeValue(FInfoNode[I], TSizeFormatter.Format(Generator.Statistics.FilterSize)); + 4: SetInfoNodeValue(FInfoNode[I], + TSizeFormatter.Format(Generator.Statistics.DefinitionSize)); + 5: SetInfoNodeValue(FInfoNode[I], + TSizeFormatter.Format(Generator.Statistics.MnemonicSize)); + 6: SetInfoNodeValue(FInfoNode[I], TSizeFormatter.Format(Generator.Statistics.FilterSize + + Generator.Statistics.DefinitionSize + Generator.Statistics.MnemonicSize)); + end; + end; + finally + TreeView.EndUpdate; + end; + Application.ProcessMessages; + finally + Generator.Free; + end; +end; + +procedure TfrmGenerator.FormCreate(Sender: TObject); + +function AddNodeData(Parent: PVirtualNode; NodeType: TGeneratorNodeType; const Text: String; + const Value: String = ''): PVirtualNode; +var + NodeData: PGeneratorNodeData; +begin + Result := TreeView.AddChild(Parent); + NodeData := TreeView.GetNodeData(Result); + if (Assigned(NodeData)) then + begin + NodeData^.NodeType := NodeType; + NodeData^.Text := Text; + case NodeType of + ntOperation: + begin + NodeData^.ProgressActive := false; + NodeData^.ProgressUpdate(0); + end; + ntValue: + NodeData^.Value := Value; + end; + end; +end; + +var + Category: PVirtualNode; +begin + TreeView.NodeDataSize := SizeOf(TGeneratorNodeData); + TreeView.BeginUpdate; + try + Category := AddNodeData(nil, ntCategory, 'Progress'); + FProgressNode[woIndexingDefinitions] := + AddNodeData(Category, ntOperation, 'Indexing definitions'); + FProgressNode[woIndexingFilters] := + AddNodeData(Category, ntOperation, 'Indexing filters'); + FProgressNode[woGeneratingFilterFiles] := + AddNodeData(Category, ntOperation, 'Generating filter files'); + FProgressNode[woGeneratingDefinitionFiles] := + AddNodeData(Category, ntOperation, 'Generating definition files'); + FProgressNode[woGeneratingMnemonicFiles] := + AddNodeData(Category, ntOperation, 'Generating mnemonic files'); + FProgressNodeTotal := + AddNodeData(Category, ntOperation, 'Total progress'); + TreeView.Expanded[Category] := true; + AddNodeData(nil, ntSpacer, ''); + Category := AddNodeData(nil, ntCategory, 'Statistics'); + FInfoNode[0] := AddNodeData(Category, ntValue, 'Filter Count', '-'); + FInfoNode[1] := AddNodeData(Category, ntValue, 'Definition Count', '-'); + FInfoNode[2] := AddNodeData(Category, ntValue, 'Mnemonic Count', '-'); + FInfoNode[3] := AddNodeData(Category, ntValue, 'Filter Size', '-'); + FInfoNode[4] := AddNodeData(Category, ntValue, 'Definition Size', '-'); + FInfoNode[5] := AddNodeData(Category, ntValue, 'MnemonicSize', '-'); + FInfoNode[6] := AddNodeData(Category, ntValue, 'TotalSize', '-'); + TreeView.Expanded[Category] := true; + finally + TreeView.EndUpdate; + end; +end; + +procedure TfrmGenerator.GeneratorWork(Sender: TObject; WorkCount: Integer); +var + Node: PVirtualNode; + NodeData: PGeneratorNodeData; + ProgressTotal: Double; +begin + NodeData := TreeView.GetNodeData(FProgressNode[FCurrentOperation]); + NodeData^.WorkCountUpdate(WorkCount); + if (NodeData^.IsProgressUpdateStep(WorkCount)) then + begin + TreeView.RepaintNode(FProgressNode[FCurrentOperation]); + ProgressTotal := 0; + for Node in FProgressNode do + begin + NodeData := TreeView.GetNodeData(Node); + ProgressTotal := ProgressTotal + NodeData^.Progress; + end; + NodeData := TreeView.GetNodeData(FProgressNodeTotal); + NodeData^.ProgressUpdate(ProgressTotal / Length(FProgressNode)); + TreeView.RepaintNode(FProgressNodeTotal); + Application.ProcessMessages; + end; +end; + +procedure TfrmGenerator.GeneratorWorkEnd(Sender: TObject); +var + NodeData: PGeneratorNodeData; +begin + NodeData := TreeView.GetNodeData(FProgressNode[FCurrentOperation]); + NodeData^.ProgressActive := false; + NodeData^.ProgressUpdate(1); + TreeView.RepaintNode(FProgressNode[FCurrentOperation]); + NodeData := TreeView.GetNodeData(FProgressNodeTotal); + if (FCurrentOperation = High(TGeneratorWorkOperation)) then + begin + NodeData^.ProgressActive := false; + end; + NodeData^.ProgressUpdate((Integer(FCurrentOperation) + 1) / Length(FProgressNode)); + TreeView.RepaintNode(FProgressNodeTotal); +end; + +procedure TfrmGenerator.GeneratorWorkStart(Sender: TObject; Operation: TGeneratorWorkOperation; + MinWorkCount, MaxWorkCount: Integer); +var + NodeData: PGeneratorNodeData; +begin + FCurrentOperation := Operation; + NodeData := TreeView.GetNodeData(FProgressNode[Operation]); + NodeData^.ProgressInit(MaxWorkCount, MinWorkCount); + NodeData^.ProgressActive := true; + TreeView.RepaintNode(FProgressNode[FCurrentOperation]); + NodeData := TreeView.GetNodeData(FProgressNodeTotal); + if (FCurrentOperation = Low(TGeneratorWorkOperation)) then + begin + NodeData^.ProgressActive := true; + TreeView.RepaintNode(FProgressNodeTotal); + end; +end; + + procedure TfrmGenerator.TreeViewBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +var + NodeData: PGeneratorNodeData; + ProgressWidth: Integer; +begin + if (Column = 1) then + begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData) and (NodeData^.NodeType = ntOperation) and + (NodeData^.Progress <> 1) and (NodeData^.Progress <> 0)) then + begin + TargetCanvas.Pen.Color := $0000A162; + TargetCanvas.Brush.Color := $0055F2B5; + TargetCanvas.Rectangle(CellRect.Left, CellRect.Top, CellRect.Right, + CellRect.Bottom - CellRect.Top); + TargetCanvas.Pen.Color := $0000A162; + TargetCanvas.Brush.Color := $000FE18E; + ProgressWidth := Round(NodeData^.Progress * (CellRect.Right - CellRect.Left)); + TargetCanvas.Rectangle(CellRect.Left, CellRect.Top, CellRect.Left + ProgressWidth, + CellRect.Bottom - CellRect.Top); + end; + end; +end; + +procedure TfrmGenerator.TreeViewCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; + var Allowed: Boolean); +begin + Allowed := false; +end; + +procedure TfrmGenerator.TreeViewFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + NodeData: PGeneratorNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + Finalize(NodeData^); + end; +end; + +procedure TfrmGenerator.TreeViewGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + NodeData: PGeneratorNodeData; +begin + ImageIndex := -1; + if (Column = 0) and (Kind in [ikNormal, ikSelected]) then + begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + case NodeData^.NodeType of + ntCategory: + ImageIndex := 0; + ntOperation: + begin + if (NodeData^.ProgressActive) then + begin + ImageIndex := 2; + end else + begin + ImageIndex := 1; + end; + end; + ntValue: + ImageIndex := 3; + end; + end; + end; +end; + +procedure TfrmGenerator.TreeViewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + NodeData: PGeneratorNodeData; +begin + CellText := ''; + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + if (NodeData^.NodeType in [ntCategory, ntOperation, ntValue]) then + begin + case Column of + 0: CellText := NodeData^.Text; + 1: CellText := NodeData^.Value; + end; + end; + end; +end; + +end. diff --git a/assets/InstructionEditor/Forms/formMain.dfm b/assets/InstructionEditor/Forms/formMain.dfm new file mode 100644 index 0000000..1fb7e43 --- /dev/null +++ b/assets/InstructionEditor/Forms/formMain.dfm @@ -0,0 +1,2508 @@ +object frmMain: TfrmMain + Left = 0 + Top = 0 + Caption = 'InstructionEditor' + ClientHeight = 761 + ClientWidth = 1084 + Color = clBtnFace + Constraints.MinHeight = 800 + Constraints.MinWidth = 1100 + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnResize = FormResize + PixelsPerInch = 96 + TextHeight = 13 + object Ribbon: TdxRibbon + Left = 0 + Top = 0 + Width = 1084 + Height = 127 + BarManager = BarManager + Style = rs2010 + ColorSchemeAccent = rcsaBlue + ColorSchemeName = 'Blue' + PopupMenuItems = [] + SupportNonClientDrawing = True + Contexts = <> + TabOrder = 1 + TabStop = False + object RibbonTab1: TdxRibbonTab + Active = True + Caption = 'Main Menu' + Groups = < + item + ToolbarName = 'barMainManu' + end + item + ToolbarName = 'barClipboard' + end + item + ToolbarName = 'barEditor' + end + item + ToolbarName = 'barView' + end + item + ToolbarName = 'barGenerator' + end> + Index = 0 + end + end + object StatusBar: TdxRibbonStatusBar + Left = 0 + Top = 736 + Width = 1084 + Height = 25 + Panels = < + item + PanelStyleClassName = 'TdxStatusBarToolbarPanelStyle' + PanelStyle.ToolbarName = 'barStatusBarProgress' + Fixed = False + Width = 300 + end + item + PanelStyleClassName = 'TdxStatusBarToolbarPanelStyle' + PanelStyle.ToolbarName = 'barMnemonicFilter' + Width = 404 + end + item + PanelStyleClassName = 'TdxStatusBarTextPanelStyle' + Text = 'Mnemonics: ' + Width = 100 + end + item + PanelStyleClassName = 'TdxStatusBarTextPanelStyle' + Text = 'Definitions: ' + Width = 100 + end + item + PanelStyleClassName = 'TdxStatusBarTextPanelStyle' + Text = 'Filters: ' + Width = 100 + end> + Ribbon = Ribbon + LookAndFeel.NativeStyle = False + Font.Charset = DEFAULT_CHARSET + Font.Color = clDefault + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + end + object Splitter: TcxSplitter + Left = 364 + Top = 127 + Width = 3 + Height = 609 + end + object pnlInspector: TPanel + Left = 0 + Top = 127 + Width = 364 + Height = 609 + Align = alLeft + BevelOuter = bvNone + TabOrder = 3 + object DockSite: TdxDockSite + Left = 0 + Top = 0 + Width = 364 + Height = 609 + Align = alClient + DockingType = 5 + OriginalWidth = 364 + OriginalHeight = 609 + object LayoutDockSite: TdxLayoutDockSite + Left = 0 + Top = 0 + Width = 364 + Height = 609 + DockingType = 0 + OriginalWidth = 300 + OriginalHeight = 200 + end + object VertContainerDockSite: TdxVertContainerDockSite + Left = 0 + Top = 0 + Width = 364 + Height = 609 + ActiveChildIndex = -1 + AllowFloating = False + AutoHide = False + CaptionButtons = [] + CustomCaptionButtons.Buttons = <> + Dockable = False + DockingType = 0 + OriginalWidth = 185 + OriginalHeight = 140 + object pnlPropertyInspector: TdxDockPanel + Left = 0 + Top = 0 + Width = 364 + Height = 431 + AllowFloating = False + AutoHide = False + Caption = 'Property Inspector' + CaptionButtons = [] + CustomCaptionButtons.Buttons = <> + Dockable = False + ImageIndex = 0 + TabsProperties.CustomButtons.Buttons = <> + DockingType = 2 + OriginalWidth = 350 + OriginalHeight = 431 + object Inspector: TcxRTTIInspector + Left = 0 + Top = 0 + Width = 350 + Height = 396 + Align = alClient + Constraints.MinWidth = 350 + LookAndFeel.NativeStyle = False + LookAndFeel.SkinName = 'Seven' + OptionsView.PaintStyle = psdotNet + OptionsView.RowHeaderMinWidth = 120 + OptionsView.RowHeaderWidth = 170 + OptionsView.ShowReadOnlyProperties = True + OptionsView.Sorted = False + TabOrder = 0 + OnItemChanged = InspectorItemChanged + Version = 1 + end + object Button1: TButton + Left = 279 + Top = -5 + Width = 75 + Height = 25 + Caption = 'Button1' + TabOrder = 1 + OnClick = Button1Click + end + object Button2: TButton + Left = 136 + Top = 104 + Width = 75 + Height = 25 + Caption = 'Button2' + TabOrder = 2 + OnClick = Button2Click + end + end + object pnlPropertyInformation: TdxDockPanel + Left = 0 + Top = 431 + Width = 364 + Height = 178 + AllowFloating = False + AutoHide = False + Caption = 'Property Information' + CaptionButtons = [cbHide] + CustomCaptionButtons.Buttons = <> + Dockable = False + ImageIndex = 1 + TabsProperties.CustomButtons.Buttons = <> + DockingType = 2 + OriginalWidth = 185 + OriginalHeight = 178 + object lblPropertyInfo: TLabel + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 344 + Height = 137 + Align = alClient + Caption = 'No info text available' + Constraints.MinHeight = 120 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + WordWrap = True + ExplicitWidth = 119 + ExplicitHeight = 120 + end + end + end + end + end + object EditorTree: TVirtualStringTree + Left = 367 + Top = 127 + Width = 717 + Height = 609 + Align = alClient + Header.AutoSizeIndex = 0 + Header.Font.Charset = DEFAULT_CHARSET + Header.Font.Color = clWindowText + Header.Font.Height = -11 + Header.Font.Name = 'Tahoma' + Header.Font.Style = [] + Header.Options = [hoAutoResize, hoColumnResize, hoShowSortGlyphs, hoVisible] + Images = imgTreeView + TabOrder = 8 + TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseBlendedSelection] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect] + TreeOptions.StringOptions = [toSaveCaptions, toShowStaticText, toAutoAcceptEditChange] + OnChange = EditorTreeChange + OnCollapsing = EditorTreeCollapsing + OnCompareNodes = EditorTreeCompareNodes + OnGetText = EditorTreeGetText + OnPaintText = EditorTreePaintText + OnGetImageIndex = EditorTreeGetImageIndex + OnKeyDown = EditorTreeKeyDown + OnMouseUp = EditorTreeMouseUp + Columns = < + item + Position = 0 + Width = 10 + WideText = 'Index' + end + item + Alignment = taRightJustify + Position = 1 + Width = 150 + WideText = 'Opcode' + end + item + Position = 2 + Width = 180 + WideText = 'Mnemonic' + end + item + Position = 3 + Width = 90 + WideText = 'OP A' + end + item + Position = 4 + Width = 90 + WideText = 'OP B' + end + item + Position = 5 + Width = 90 + WideText = 'OP C' + end + item + Position = 6 + Width = 90 + WideText = 'OP D' + end + item + Position = 7 + Width = 150 + WideText = 'Comment' + end> + end + object BarManager: TdxBarManager + AlwaysSaveText = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Segoe UI' + Font.Style = [] + Categories.Strings = ( + 'Default') + Categories.ItemsVisibles = ( + 2) + Categories.Visibles = ( + True) + ImageOptions.Images = imgIcons16 + ImageOptions.LargeImages = imgIcons32 + LookAndFeel.NativeStyle = True + LookAndFeel.SkinName = 'Seven' + PopupMenuLinks = <> + UseSystemFont = True + Left = 552 + Top = 176 + DockControlHeights = ( + 0 + 0 + 0 + 0) + object barMainManu: TdxBar + Caption = 'Main Menu' + CaptionButtons = <> + DockedLeft = 0 + DockedTop = 0 + FloatLeft = 1118 + FloatTop = 8 + FloatClientWidth = 0 + FloatClientHeight = 0 + ItemLinks = < + item + Visible = True + ItemName = 'lbLoadDatabase' + end + item + Visible = True + ItemName = 'lbSaveDatabase' + end> + OneOnRow = False + Row = 0 + UseOwnFont = False + Visible = True + WholeRow = False + end + object barEditor: TdxBar + Caption = 'Editor' + CaptionButtons = <> + DockedLeft = 328 + DockedTop = 0 + FloatLeft = 1118 + FloatTop = 8 + FloatClientWidth = 0 + FloatClientHeight = 0 + ItemLinks = < + item + Visible = True + ItemName = 'lbCreateDefinition' + end + item + Distributed = False + Visible = True + ItemName = 'bbDuplicateDefinition' + end + item + Distributed = False + Visible = True + ItemName = 'bbDeleteDefinition' + end> + OneOnRow = False + Row = 0 + UseOwnFont = False + Visible = True + WholeRow = False + end + object barStatusBarProgress: TdxBar + Caption = 'Statusbar Progress' + CaptionButtons = <> + DockedLeft = 0 + DockedTop = 0 + FloatLeft = 1118 + FloatTop = 8 + FloatClientWidth = 0 + FloatClientHeight = 0 + ItemLinks = < + item + ViewLevels = [ivlSmallIconWithText] + Visible = True + ItemName = 'piStatusBarProgress' + end> + OneOnRow = True + Row = 0 + UseOwnFont = False + Visible = True + WholeRow = True + end + object barView: TdxBar + Caption = 'View' + CaptionButtons = <> + DockedLeft = 539 + DockedTop = 0 + FloatLeft = 1118 + FloatTop = 8 + FloatClientWidth = 0 + FloatClientHeight = 0 + ItemLinks = < + item + Visible = True + ItemName = 'lbMnemonicFilter' + end + item + BeginGroup = True + Distributed = False + Visible = True + ItemName = 'bbExpandNodes' + end + item + Distributed = False + Visible = True + ItemName = 'bbCollapseNodes' + end> + OneOnRow = False + Row = 0 + UseOwnFont = False + Visible = True + WholeRow = False + end + object barGenerator: TdxBar + Caption = 'Generator' + CaptionButtons = <> + DockedLeft = 754 + DockedTop = 0 + FloatLeft = 1118 + FloatTop = 8 + FloatClientWidth = 0 + FloatClientHeight = 0 + ItemLinks = < + item + Visible = True + ItemName = 'lbGenerate' + end> + OneOnRow = False + Row = 0 + UseOwnFont = False + Visible = True + WholeRow = False + end + object barClipboard: TdxBar + Caption = 'Clipboard' + CaptionButtons = <> + DockedLeft = 139 + DockedTop = 0 + FloatLeft = 1118 + FloatTop = 8 + FloatClientWidth = 0 + FloatClientHeight = 0 + ItemLinks = < + item + Visible = True + ItemName = 'lbClipboardPaste' + end + item + Distributed = False + Visible = True + ItemName = 'bbClipboardCopy' + end + item + Distributed = False + Visible = True + ItemName = 'bbClipboardCut' + end> + OneOnRow = False + Row = 0 + UseOwnFont = False + Visible = True + WholeRow = False + end + object barMnemonicFilter: TdxBar + AllowClose = False + AllowCustomizing = False + AllowQuickCustomizing = False + Caption = 'Mnemonic Filter' + CaptionButtons = <> + DockedLeft = 0 + DockedTop = 0 + FloatLeft = 823 + FloatTop = 779 + FloatClientWidth = 100 + FloatClientHeight = 46 + ItemLinks = < + item + UserDefine = [udWidth] + UserWidth = 215 + ViewLevels = [ivlSmallIconWithText] + Visible = True + ItemName = 'edtMnemonicFilter' + end + item + UserDefine = [udPaintStyle] + UserPaintStyle = psCaptionGlyph + ViewLevels = [ivlSmallIconWithText] + Visible = True + ItemName = 'bbExactMatch' + end> + NotDocking = [dsNone, dsLeft, dsTop, dsRight, dsBottom] + OneOnRow = True + Row = 0 + UseOwnFont = False + Visible = True + WholeRow = True + end + object lbLoadDatabase: TdxBarLargeButton + Caption = 'Load Database' + Category = 0 + Hint = 'Load Database' + Visible = ivAlways + LargeImageIndex = 0 + OnClick = lbLoadDatabaseClick + SyncImageIndex = False + ImageIndex = 0 + end + object lbSaveDatabase: TdxBarLargeButton + Caption = 'Save Database' + Category = 0 + Enabled = False + Hint = 'Save Database' + Visible = ivAlways + LargeImageIndex = 1 + ShortCut = 16467 + OnClick = lbSaveDatabaseClick + end + object lbCreateDefinition: TdxBarLargeButton + Caption = 'Create Definition' + Category = 0 + Hint = 'Create Definition' + Visible = ivAlways + LargeImageIndex = 2 + OnClick = lbCreateDefinitionClick + end + object piStatusBarProgress: TdxBarProgressItem + Align = iaClient + Caption = 'Working' + Category = 0 + Hint = 'Working' + Visible = ivInCustomizing + Width = 300 + Position = 30 + Smooth = True + end + object bbDuplicateDefinition: TdxBarButton + Align = iaClient + Caption = 'Duplicate Definition' + Category = 0 + Enabled = False + Hint = 'Duplicate Definition' + Visible = ivAlways + ImageIndex = 4 + OnClick = bbDuplicateDefinitionClick + end + object bbDeleteDefinition: TdxBarButton + Align = iaClient + Caption = 'Delete Definition' + Category = 0 + Enabled = False + Hint = 'Delete Definition' + Visible = ivAlways + ImageIndex = 5 + OnClick = bbDeleteDefinitionClick + end + object lbGenerate: TdxBarLargeButton + Caption = 'Generate C++ Files' + Category = 0 + Hint = 'Generate C++ Files' + Visible = ivAlways + LargeImageIndex = 5 + OnClick = lbGenerateClick + AutoGrayScale = False + SyncImageIndex = False + ImageIndex = 3 + end + object dxBarSeparator1: TdxBarSeparator + Caption = 'Editor' + Category = 0 + Hint = 'Editor' + Visible = ivAlways + end + object dxBarSeparator2: TdxBarSeparator + Category = 0 + Visible = ivAlways + ShowCaption = False + end + object dxBarSeparator3: TdxBarSeparator + Caption = 'Clipboard' + Category = 0 + Hint = 'Clipboard' + Visible = ivAlways + end + object bbClipboardCopy: TdxBarButton + Align = iaClient + Caption = 'Copy Definition' + Category = 0 + Enabled = False + Hint = 'Copy Definition' + Visible = ivAlways + ImageIndex = 8 + OnClick = bbClipboardCopyClick + end + object lbClipboardPaste: TdxBarLargeButton + Caption = 'Paste Definition' + Category = 0 + Hint = 'Paste Definition' + Visible = ivAlways + LargeImageIndex = 6 + OnClick = lbClipboardPasteClick + SyncImageIndex = False + ImageIndex = 9 + end + object bbClipboardCut: TdxBarButton + Align = iaClient + Caption = 'Cut Definition' + Category = 0 + Enabled = False + Hint = 'Cut Definition' + Visible = ivAlways + ImageIndex = 10 + OnClick = bbClipboardCutClick + end + object lbMnemonicFilter: TdxBarLargeButton + Caption = 'Mnemonic Filter' + Category = 0 + Hint = 'Mnemonic Filter' + Visible = ivAlways + AllowAllUp = True + ButtonStyle = bsChecked + LargeImageIndex = 7 + OnClick = lbMnemonicFilterClick + end + object bbExpandNodes: TdxBarButton + Align = iaClient + Caption = 'Expand all nodes' + Category = 0 + Hint = 'Expand all nodes' + Visible = ivAlways + ImageIndex = 6 + OnClick = bbExpandNodesClick + end + object bbCollapseNodes: TdxBarButton + Align = iaClient + Caption = 'Collapse all nodes' + Category = 0 + Hint = 'Collapse all nodes' + Visible = ivAlways + ImageIndex = 7 + OnClick = bbCollapseNodesClick + end + object edtMnemonicFilter: TdxBarEdit + Caption = 'Mnemonic Filter' + Category = 0 + Hint = 'Mnemonic Filter' + Visible = ivAlways + OnCurChange = edtMnemonicFilterCurChange + ShowCaption = True + end + object bbExactMatch: TdxBarButton + Caption = 'Exact Match' + Category = 0 + Hint = 'Exact Match' + Visible = ivAlways + AllowAllUp = True + ButtonStyle = bsChecked + ImageIndex = 11 + OnClick = bbExactMatchClick + end + object dxBarSeparator4: TdxBarSeparator + Caption = 'New Separator' + Category = 0 + Hint = 'New Separator' + Visible = ivAlways + ShowCaption = False + end + object bbExpandLeaf: TdxBarButton + Caption = 'Expand' + Category = 0 + Hint = 'Expand' + Visible = ivAlways + ImageIndex = 6 + OnClick = bbExpandLeafClick + end + object bbCollapseLeaf: TdxBarButton + Caption = 'Collapse' + Category = 0 + Hint = 'Collapse' + Visible = ivAlways + ImageIndex = 7 + OnClick = bbCollapseLeafClick + end + end + object SkinController: TdxSkinController + SkinName = 'Seven' + Left = 552 + Top = 240 + end + object imgIcons16: TcxImageList + FormatVersion = 1 + DesignInfo = 11534744 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000220000 + 0033000000330000003300000033000000330000002200000000000000000000 + 000000000000000000000000000000000000000000000000002A77736BBCB0AA + 9EFFAFA99DFFAEA89CFFAEA99CFFB0AA9EFF77736BBC0000002B000000000000 + 000B0000000A0000000A0000000A0000000A000000079B8F81DBBAB3A6FFD3CA + C1FFE4DAD2FFEFE4DDFFE8DDD6FFD5CDC4FFB9B4A7FF959085DD0000002F0F21 + 2D5F0E1F2A5C0E1F2A5C0E1F2A5C0D1D285908161F51BCAD9AFFCBC3B8FFD4CC + C4FFE1D6CEFFEBE1D9FFE4DAD2FFD7D0C7FFCDC6BCFFB1AB9FFF4190C5F14398 + D2FF4094D0FF3E92CFFF3E92CEFF3D92D0FF3592D5FFBAAA98FFCAC2B7FFD3CB + C2FFDFD5CDFFEAE0D8FFE3D8D0FFD6CEC5FFCCC5BBFFB0AA9EFF4499D2FF3F94 + D0FFABFBFFFF9BF3FFFF92F1FFFF92F1FFFF8CF4FFFFB6A695FFC8BFB4FFD1C8 + C0FFDED3CBFFE8DED6FFE1D6CEFFD4CCC3FFCAC3B9FFB0AA9EFF4397D1FF56AC + DDFF8EDAF5FFA2EDFFFF82E5FEFF83E6FFFF7EEAFFFFB4A493FFE5DDD5FFF8F4 + EEFFFDF9F2FFF9F5EDFFFDF8F2FFF9F4EEFFE6DFD8FFAEA99CFF4296D1FF71C4 + EAFF6CBCE6FFBBF2FFFF75DEFDFF75DFFEFF73E3FFFFB4A392FFF0E5DCFFDDD3 + C8FFD8CFC5FFD8CFC5FFD8CFC5FFDDD3C8FFEFE7DEFFB0A99CFF4095D0FF90DD + F8FF44A0D8FFDDFCFFFFDAFAFFFFDAFAFFFFD9FDFFFFA5B3AEFFD1C2B4FFEBE0 + D5FFEDE4DAFFEDE4DAFFEDE4DAFFEAE0D5FFD0C4B6FF928779D13E93CFFFB2F6 + FFFF51ACDEFF358ACAFF358ACAFF358ACBFF348BCDFF5ABDEAFF94BDC4FFAEA6 + 99FFAFA393FFAEA393FFAEA293FFB1A89AFFAFC0C2FF2C6A94C43D92CFFFB8F3 + FFFF77DFFEFF7BE0FEFF7CE1FEFF7CE1FFFF7DE2FFFF50ACE0FF51BBEDFFD3FB + FFFFCFFAFFFFCEF9FFFFCEF9FFFFD0FAFFFFD7FEFFFF3B95D3FF3C92CFFFC0F3 + FFFF70D9FBFF73DAFBFF74DAFBFF74DAFBFF74DBFCFF76DEFDFF4FAADDFF358C + CBFF338CCCFF328CCCFF328DCDFF3690CFFF3C94D0FF2D688FAE3B92CFFFCAF6 + FFFF69D5F9FF6CD5F9FF6AD4F9FF69D4F9FF69D5F9FF6AD6FAFF6BD8FBFF6BD9 + FCFF6BDAFDFF69DAFDFFDAFDFFFF3C93D0FF0A171F2F000000003B92CFFFD5F7 + FFFF60D1F9FF61D0F8FFB4EBFDFFD9F6FFFFDAF8FFFFDAF8FFFFDAF9FFFFDBF9 + FFFFDAF9FFFFDAFAFFFFDFFEFFFF3D94D0FF0E202C35000000003D94D0FFDCFC + FFFFD8F7FFFFD8F7FFFFDBFAFFFF358ECDFF3991CEFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3A92CFFF3D94D0FF3D8BC1EA00000000000000003F8EC5EF3D94 + D0FF3A92CFFF3A92CFFF3D94D0FF3A87BBE40B1A232B0D1E29320E1E2A330E1E + 2A330E1E2A330E1F2A330F212E37000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000190000 + 0033000000330000003300000033000000330000000800000008000000330000 + 003300000033000000330000003300000033000000330000001959400C96B782 + 18FFB68014FFB37A06FFD7CFD2FFD8CEC9FF232221531D130053D9CFCEFFD5CA + C3FFD4CAC4FFD6CFD2FFB37A06FFB68014FFB78218FF59400C96B78218FFF6CD + 8BFFF2C67DFFF0C171FFFAF7FBFFFFFFFFFF4C4848FF989392FFFFFFFFFFF7EF + EAFFF6EFEBFFF9F6FAFFF0C171FFF2C67DFFF6CD8BFFB78218FFB68116FFF3CA + 87FFEDBC6DFFEBB761FFF8F5F7FFFFFFFFFF4A4541FF948C88FFFFFFFFFFF1E8 + E0FFF0E7E0FFF7F4F7FFEBB761FFEDBC6DFFF3CA87FFB68116FFB68116FFF1CB + 89FFE9B762FFE7B257FFF9F8FBFFFDF7F2FF877F79FF4A4441FFFEF7F2FFEEE3 + D8FFEDE2D9FFF8F7FBFFE8B257FFE9B762FFF1CB89FFB68116FFB68116FFF3CC + 8EFFE8B25AFFE7AE51FFFCFFFFFFECE0D7FFF1E4DAFFF1E5DAFFEDE0D5FFEADD + D3FFE9DED5FFFBFFFFFFE7AE51FFE8B25AFFF3CC8EFFB68116FFB68115FFF3CE + 94FFE6AE51FFE5AB4BFFE6C9A4FFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFDFF + FFFFFEFFFFFFE6C9A4FFE5AC4BFFE6AE51FFF3CE94FFB68115FFB68115FFF3D0 + 9AFFE5A845FFE3A640FFE2A136FFE29E2FFFE19D2DFFE19D2CFFE19D2CFFE19D + 2DFFE29E2FFFE2A136FFE3A640FFE5A845FFF3D09AFFB68115FFB68114FFF4D4 + A0FFE1A136FFF2DEB7FFFCFFFFFFFBFFFDFFFBFFFCFFFBFFFDFFFBFFFDFFFBFF + FDFFFBFFFDFFFBFFFFFFF2DEB7FFE1A136FFF4D4A0FFB68114FFB68014FFF6D8 + A7FFE09C27FFFBFFFFFFFCFBF3FFFCF9EFFFFBF8EEFFFCFAF0FFFCFAF0FFFBF9 + EEFFF9F8EDFFFAF9F1FFFAFEFEFFE09B27FFF6D8A7FFB68014FFB68014FFF8DC + B0FFE0981CFFFBFBF8FF79787BFFA2A0A2FFFCF6EAFF797879FFA3A1A3FFA09F + A1FFFAF4E9FF9D9DA0FFF9F9F6FFE0981CFFF8DCB0FFB68014FFB68113FFFCE3 + BCFF9B6104FFFDFCF9FFFDF5E8FFFEF4E7FFFBF2E5FFFCF2E5FFFBF2E5FFFBF2 + E5FFFAF1E3FFF9F1E5FFFCFAF7FF9A6104FFFCE3BCFFB68113FFB68012FFFEE9 + C6FF714100FFFFFFFFFF79797AFF7A7A7AFFA2A1A1FF9F9F9FFFF6ECDEFF7777 + 77FFA1A1A1FF9E9FA0FFFFFFFFFF704100FFFEE9C6FFB68012FFB68012FFFDEC + D1FFDA8600FFFFFFFFFFF1E5D8FFF2E5D8FFF2E5D7FFF0E3D6FFEFE2D5FFF1E4 + D7FFF1E4D6FFEFE3D6FFFFFFFFFFDA8600FFFDECD1FFB68012FFB78115FFFFEC + CDFFFCE7C3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE7C3FFFFECCDFFB78115FF593F0C7CB781 + 14FFB57E0FFFB57C0BFFB57C09FFB57C09FFB57C09FFB57C09FFB57C09FFB57C + 09FFB57C09FFB57C09FFB57C0BFFB57E0FFFB78114FF593F0C7C} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000002200000033000000330000003300000033000000330000 + 0033000000330000002300000000000000000000000000000000000000000000 + 000A000000258C6839BCCE9956FFCE964EFFAFB4BAFFB1B1B2FFB1B1B1FFB1B1 + B1FFB2B2B2FF7C7C7CBF000000000000000000000000000000000000001F2323 + 205C7E7C77C5D09851FFEDDEBAFFE6CF9FFFFAFCFFFFFAF9FAFFFAF9F9FFFAF9 + F9FFFFFFFFFFB2B2B2FF000000330000002300000000000000006B6760ADB4AF + A4FFC4C1BBFFCE964EFFEBD9B5FFE1C38CFFF0F3F7FFEFF0F0FFEFEFEEFFF0F0 + EFFFF9F9F8FFB0B0B0FFB3B3B3FF7C7C7CBE0000000000000000B1AB9FFFC8C2 + B7FFD0CBC8FFCD954DFFECDAB7FFDEBB7EFFEBECF1FFEAE9E9FFEAE9E8FFEAE9 + E8FFF6F6F5FFADADADFFFFFFFFFFB3B3B3FF0000003300000023B0AB9EFFC8C1 + B8FFCEC9C6FFCC944BFFEFDCBBFFDCB36FFFE5E7EBFFE4E4E3FFE4E3E2FFE5E3 + E2FFF5F5F4FFACACACFFFEFEFCFFB0B1B1FFB3B3B3FF7C7C7CBFB0AA9EFFCAC3 + BAFFECEAE7FFCC944AFFF2E2C3FFF2DEBBFFF6F8FCFFF6F5F5FFF5F4F4FFF5F4 + F4FFF7F6F6FFACACADFFFAFAF9FFAEAEAEFFFFFFFFFFB3B3B3FF6F6B64ADF9F4 + EEFFD8D4CFFFC59F6EFFD09749FFD59843FFB5B7B2FFB3B3ADFFAFAFACFFADAD + ACFFACADADFFC3C3C2FFF8F8F7FFADADADFFFEFEFDFFB2B2B2FF706C64B4A39A + 8FFFBAB3AAFFCCC5BEFFE7E0D3FF1F39DCFF9DAFFFFF98A9FFFFFFFEF7FFFCF9 + F8FFF9F7F7FFF8F7F7FFF8F7F7FFACACADFFFBFBFAFFB2B2B2FFB1AB9FFFC9C2 + B9FFCFC8BFFFD7CEC6FFE5DBCBFF7179D3FF293BD5FF2D39D8FFC3B6B1FFB9B0 + B1FFB1AEAEFFADADADFFADADADFFC3C3C2FFF9F9F8FFB2B2B2FFB0AB9EFFC7C0 + B6FFCCC4BBFFD3CAC1FFDDD3C7FFEDDFD0FFFFF0E0FF009B5AFF79EBD3FF6EE6 + D0FFFFF9FCFFFBF8F9FFF9F8F8FFF9F7F8FFFAF9F9FFB3B3B3FFAFAA9DFFC8C1 + B7FFE8E3DBFFF5F0E8FFFDF9F2FFFFF9F2FFFFFDF6FF4CBC98FF00955FFF0094 + 5CFFB9AFB3FFB0AFB1FFB1B1B2FFB2B2B2FFB3B3B3FF7D7D7DB0AEA89CFFFBF5 + EFFFEEE7DEFFE0D8CEFFDDD5CCFFDDD5CCFFE2D6CEFFEBD9D2FFF1DBD5FFF1DD + D6FFF6E9E1FFFDF7EEFFAEA799FF000000000000000000000000AFA99DFFE1D8 + CEFFE1D7CEFFDFD6CCFFDFD5CBFFDFD5CBFFDFD6CCFFE1D6CCFFE2D6CDFFE2D7 + CDFFE2D8CEFFE2D8CEFFAFA99CFF0000000000000000000000006A675F99B6B0 + A4FFD6CFC4FFE6DED5FFEFE7DDFFEEE6DCFFEEE6DCFFEEE6DCFFEFE7DDFFE6DE + D5FFD6CFC4FFB6B0A4FF6A675F99000000000000000000000000000000002322 + 2033827D74BCAEA99CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA9 + 9CFF827D74BC2322203300000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000002200000033000000330000 + 0033000000330000003300000033000000330000003300000030000000000000 + 00000000000000000023000000330000003372665BB9AB9787FFAB9584FFAA95 + 84FFA99584FFA99585FFA99585FFA99685FFAA9787FFA39183F2000000000000 + 000000000000786A60BFAB9887FFAA9787FFA99584FFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA9787FF000000300000 + 003300000033AA9686FFFFFFFFFFFFFFFFFFA58F7EFFFFFFFFFF00A4FFFF00A4 + FFFFFFFCFAFFBFA282FFBFA385FFBDA282FFFFFFFFFFA89585FFA39183F2AA98 + 88FFAA9686FFA69282FFFFFFFFFFC0A485FFA38E7EFFFFFFFFFFF8F3F3FFF9F4 + F6FFF3F4F9FFF1F5FDFFF0F5FEFFEFF3F9FFFFFFFFFFA89584FFAA9787FFFFFF + FFFFFFFFFFFFA39080FFFFFFFFFFFEFFFFFFA28F7FFFFFFFFFFFCE8C2DFFCF8E + 33FFCE8F34FFCE8F35FFCD8F34FFCC8C2EFFFFFFFFFFA89585FFA89586FFFFFF + FFFFCE8F32FFA39185FFFFFFFFFFE5A84CFFA39183FFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA9787FFA89586FFFFFF + FFFFCE9138FFA49388FFFFFFFFFFC58223FFC3B8B2FFA58F7FFFA58E7EFFA58E + 7EFFA58E7EFFA48E7EFFA48F7FFFA79382FFAA9787FFA29082EDA89586FFFFFF + FFFFCB8E35FFA59489FFFFFFFFFFF2EEF4FFF7F0F5FFF9F1F5FFF9F1F5FFF9F1 + F5FFF8F0F4FFF5EFF2FFFFFFFFFFAA9686FF0000000000000000A89686FFFFFF + FFFFC6892FFFA69489FFFFFFFFFF30A977FF37AB7AFF38AC7BFF38AC7BFF38AC + 7BFF37AB7AFF31A977FFFFFFFFFFAA9585FF0000000000000000A99686FFFFFF + FFFFC3832AFFA7978EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFAB9787FF0000000000000000A99686FFFFFF + FFFFBC8027FFB49571FFA89991FFA7968CFFA8968CFFA8958BFFA7958BFFA795 + 8AFFA69386FFA59081FFA99584FF72665CA80000000000000000A99686FFFFFF + FFFFBA7D26FFBF8532FFC58D3AFFCA9342FFCE9849FFCF9A4FFFD09D53FFCE9D + 53FFCA964CFFFFFFFFFFAA9687FF000000000000000000000000A99686FFFFFF + FFFFB7781DFFBA7D27FFBC7F2BFFBE8431FFC18838FFC28C3EFFC38E42FFC491 + 45FFC58F43FFFFFFFFFFA99686FF000000000000000000000000AA9787FFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFAA9787FF000000000000000000000000A39183EFAA97 + 87FFA99686FFA99686FFA99686FFA99686FFA99686FFA89686FFA89686FFA895 + 86FFA99586FFAA9787FFA39183EF000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000330000003300000000000000000000000000000000000000000000 + 000A000000260000003300000033000000330000003300000033000000330000 + 00336C6A69FF6C6A69FF0000000E0000003300000033000000000000001F2322 + 205C837E75C9B0AA9EFFAFA99DFFAEA89CFFC9C3B6FF73716FFF777573FFCBC4 + B8FF999796FF999796FF1C1C1C69777573FF73716FFF000000006B6760ADB4AE + A2FFC5BEB3FFD4CAC2FFE1D7CFFFE8DED6FFFBEFE8FF7F7D7BFFC7C4C3FF8684 + 83FFBCBAB9FFBCBAB9FF868483FFC7C4C3FF787675FF00000000B1AB9FFFC8C1 + B6FFCFC7BFFFD6CCC5FFDCD3CAFFE9DDD6FFFFFFFFFFC2BEB8FF878584FFA9A7 + A6FF817F7DFF817F7DFFA9A7A6FF878584FF2E2D2C8900000033B0AB9EFFC7C0 + B6FFCDC4BBFFD3CAC2FFDAD1C8FFFFFFFCFF716F6DFFA19F9EFFC1BFBDFF8380 + 7FFFFCF2E6FFF5EAE0FF83807FFFC1BFBDFFA09E9DFF7B7977FFB0AA9EFFCAC3 + B9FFEAE5DDFFF7F3EBFFFFFBF4FFFFFFFBFF72706EFFA3A09FFFC4C2C1FF8684 + 80FFEFEEEEFFD1CAC1FF868480FFC3C1C1FFA19F9EFF7C7A78FF6F6B64ADF9F3 + EDFFD8D1C9FFC2B8B0FFBFB6AEFFC5BAB2FFE1D5CBFFA8A09BFF8C8A88FFB2AF + AEFF878584FF878584FFB2AFAEFF8C8A88FF3837369B00000000706C64B4A39A + 8FFFBAB2A7FFCAC1B8FFDED5CCFFE5DBD3FFFFFFFFFF868481FFD5D3D2FF8D8B + 89FFC9C7C6FFC9C7C6FF8D8B89FFD5D3D2FF7F7D7BFF00000000B1AB9FFFC9C2 + B9FFCFC7BFFFD5CCC4FFDCD3CAFFE3D9D1FFF7EBE4FF7A7876FF878583FFD9D9 + D8FFA9A7A5FFA9A7A5FFC0BBAFFF878583FF7B7977FF00000000B0AB9EFFC7C0 + B6FFCCC4BBFFD3C9C1FFDAD0C7FFE1D7CFFFEBE1DAFFF4E8DFFFFFFBF2FFF3E9 + DDFF767472FF767472FFBDB6AAFF000000000000000000000000AFAA9DFFC8C1 + B7FFE8E3DBFFF5F0E8FFFDF8F2FFFCF8F1FFFBF7F0FFFCF7F1FFFCF8F1FFF6F0 + EAFFE9E2DBFFCAC2BAFFAFA99DFF000000000000000000000000AEA89CFFFBF5 + EFFFEEE7DEFFE0D8CEFFDDD5CCFFDDD4CBFFDDD4CBFFDDD4CBFFDDD5CCFFE0D7 + CEFFEDE6DEFFFBF6EFFFAEA89CFF000000000000000000000000AFA99DFFE1D8 + CEFFE1D7CEFFDFD6CCFFDFD5CBFFDFD5CBFFDFD5CBFFDFD5CBFFDFD5CBFFDFD6 + CCFFE1D7CEFFE1D8CEFFAFA99DFF0000000000000000000000006A675F99B6B0 + A4FFD6CFC4FFE6DED5FFEFE7DDFFEEE6DCFFEEE6DCFFEEE6DCFFEFE7DDFFE6DE + D5FFD6CFC4FFB6B0A4FF6A675F99000000000000000000000000000000002322 + 2033827D74BCAEA99CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA9 + 9CFF827D74BC2322203300000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000001E0000003300000033000000330000001E00000000000000000000 + 000A000000260000003300000033000000330000003300000033000000330000 + 00331C2A79A9374DCCFF384DCBFF384DCCFF212F79AC0000001E0000001F2322 + 205C837E75C9B0AA9EFFAFA99DFFAEA89CFFAEA89CFFB0AA9CFFB9B199FF6C76 + B8FF324ED9FF375CF9FF375DFAFF385DF9FF3852D7FF202E79AC6B6760ADB4AE + A2FFC5BEB3FFD4CAC2FFE1D7CFFFE8DED6FFEFE4DDFFEDE2D8FFF0E3CEFF213C + CEFF3E62FCFF3B60FAFF3A5DF8FF3C60FAFF4165FBFF344BCCFFB1AB9FFFC8C1 + B6FFCFC7BFFFD6CCC5FFDCD3CAFFE4D9D2FFEBE0D9FFE8DED4FFEEE0CAFF1F39 + CBFFA6B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFA9BAFFFF3148CAFFB0AB9EFFC7C0 + B6FFCDC4BBFFD3CAC2FFDAD1C8FFE2D7CFFFECE1DAFFE7DBD1FFEBDDC9FF1C37 + CAFF5875FEFF5775FEFF5473FDFF5776FEFF5D79FFFF334ACBFFB0AA9EFFCAC3 + B9FFEAE5DDFFF7F3EBFFFFFBF4FFFDFAF3FFFDF9F2FFFFFAF3FFFFFFF3FF8993 + DDFF3954DEFF6C86FFFF728AFFFF6F89FFFF465EDDFF1F2D79976F6B64ADF9F3 + EDFFD8D1C9FFC2B8B0FFBFB6AEFFC5BAB2FFC8BEB5FFC6BCB3FFC4BAAFFFD1C5 + B2FF6771BAFF233ED0FF2942CEFF2F47CDFF1F2D799700000000706C64B4A39A + 8FFFBAB2A7FFCAC1B8FFDED5CCFFE5DBD3FFECE1DAFFE8DED5FFE1D7CEFFD1C6 + BBFFC6BBAAFFB4A790FF746D5AAB000000000000000000000000B1AB9FFFC9C2 + B9FFCFC7BFFFD5CCC4FFDCD3CAFFE3D9D1FFEADFD8FFE5DCD3FFDED4CCFFD8CF + C5FFD3CBC1FFCEC6BAFFB7B09DFF000000000000000000000000B0AB9EFFC7C0 + B6FFCCC4BBFFD3C9C1FFDAD0C7FFE1D7CFFFEBE1DAFFE4D9D1FFDCD1C9FFD5CC + C2FFCEC6BDFFCAC1B9FFB1AB9EFF000000000000000000000000AFAA9DFFC8C1 + B7FFE8E3DBFFF5F0E8FFFDF8F2FFFCF8F1FFFBF7F0FFFCF7F1FFFCF8F1FFF6F0 + EAFFE9E2DBFFCAC2BAFFAFA99DFF000000000000000000000000AEA89CFFFBF5 + EFFFEEE7DEFFE0D8CEFFDDD5CCFFDDD4CBFFDDD4CBFFDDD4CBFFDDD5CCFFE0D7 + CEFFEDE6DEFFFBF6EFFFAEA89CFF000000000000000000000000AFA99DFFE1D8 + CEFFE1D7CEFFDFD6CCFFDFD5CBFFDFD5CBFFDFD5CBFFDFD5CBFFDFD5CBFFDFD6 + CCFFE1D7CEFFE1D8CEFFAFA99DFF0000000000000000000000006A675F99B6B0 + A4FFD6CFC4FFE6DED5FFEFE7DDFFEEE6DCFFEEE6DCFFEEE6DCFFEFE7DDFFE6DE + D5FFD6CFC4FFB6B0A4FF6A675F99000000000000000000000000000000002322 + 2033827D74BCAEA99CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA9 + 9CFF827D74BC2322203300000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000300000 + 0033000000330000003300000033000000330000003300000033000000330000 + 003300000033000000330000003300000033000000330000003000652DF20067 + 2EFF00662EFF00672DFF006D25FF0A32A7FF0B369CFF0C3699FF0C3699FF0B36 + 9CFF0A32A7FF006D25FF00672DFF00662EFF00672EFF00652DF200682EFF98E9 + AAFF26BF4CFF29C14CFF2DC845FF0933A8FF187AE3FF0A6FDBFF0A6FDBFF187A + E3FF0933A8FF2DC845FF29C14CFF26BF4CFF98E9AAFF00682EFF00672DFFA7D2 + 99FFA2CE96FFA4CF95FFADD58CFF0233A9FF3187E3FF0C6ED7FF0C6ED7FF3187 + E3FF0233A9FFADD58CFFA4CF95FFA2CE96FFA7D299FF00672DFF995105FFAD45 + 00FFA84300FFAA4400FFB64300FF1582F0FF2CAEFFFF30AEFFFF30AEFFFF2CAE + FFFF1582F0FFB64300FFAA4400FFA84300FFAD4500FF995005FFAC4F00FFFFC4 + B1FFF87D52FFFA7D51FFFF7A44FF30BDFFFF3DBAFFFF0E71DAFF0E71DAFF3DBA + FFFF30BDFFFFFF7A44FFFA7D51FFF87D53FFFFC4B2FFAB4E00FFA94F00FFD1AB + B9FFCFA9B2FFD0A7B0FFD7A1A6FF46CEFFFF4AC8FFFF1688E9FF1688E9FF4AC8 + FFFF46CEFFFFD7A1A6FFD0A7B0FFCFA9B2FFD0ABBAFFB35400FF261580FF0000 + 9AFF000093FF000091FF00008CFF35A6ECFFECFFFFFFE8FFFFFFE8FFFFFFECFF + FFFF35A6ECFF00008CFF000091FF000093FF00009BFF402166FF090699FFABCD + FFFF4A81FFFF4A80FFFF4479FFFFD2E3F9FFA6957BFFB9772BFFB9772BFFA695 + 7BFFD2E3F9FF4479FFFF4A80FFFF4A81FFFFAACDFFFF07059AFF0C0796FFCCE9 + FFFFC6E0FFFFC4DEFFFFBCD7FFFFCCE6FFFFB97A2EFFF8C87EFFF8C87EFFB97A + 2EFFCCE6FFFFBCD7FFFFC4DEFFFFC6E0FFFFCCE9FFFF0B0796FF110D8FEF0B06 + 95FF070193FF000094FF000097FFCDEEFFFFB77D35FFF0C582FFEDBB6EFFB77D + 36FFCDEEFFFF000097FF000094FF070193FF0B0695FF0C0A6AB0000000000000 + 00000000000000000000795520ACBD8338FFB57E3BFFEAC387FFE3B064FFB57E + 3CFFBD8338FF795520AC00000000000000000000000000000000000000000000 + 00000000000000000000C18A3FFFF2D093FFDCA75AFFD9A65AFFDAA65AFFDCA7 + 5AFFF2D093FFC18A3FFF00000000000000000000000000000000000000000000 + 0000000000000000000000000000B78141FFE5C791FED19C4DFFD19C4DFFE5C7 + 91FEB78141FF0000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000B78141FFCDB389EACDB389EAB781 + 41FF000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B88342FFB88342FF0000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000300000 + 0033000000330000003300000033000000330000003300000033000000330000 + 003300000033000000330000003300000033000000330000003000652DF20067 + 2EFF00662EFF00672DFF006D25FF0A32A7FF0B369CFF0C3699FF0C3699FF0B36 + 9CFF0A32A7FF006D25FF00672DFF00662EFF00672EFF00652DF200682EFF98E9 + AAFF26BF4CFF29C14CFF2DC845FF0933A8FF187AE3FF0A6FDBFF0A6FDBFF187A + E3FF0933A8FF2DC845FF29C14CFF26BF4CFF98E9AAFF00682EFF00672DFFA7D2 + 99FFA2CE96FFA4CF95FFADD58CFF0233A9FF3187E3FF0C6ED7FF0C6ED7FF3187 + E3FF0233A9FFADD58CFFA4CF95FFA2CE96FFA7D299FF00672DFF995105FFAD45 + 00FFA84300FFAA4400FFB64300FF1582F0FF2CAEFFFF30AEFFFF30AEFFFF2CAE + FFFF1582F0FFB64300FFAA4400FFA84300FFAD4500FF995005FFAC4F00FFFFC4 + B1FFF87D52FFFA7D51FFFF7A44FF31BDFFFF3EBAFFFF0E72DAFF0E72DAFF3EBA + FFFF31BDFFFFFF7A44FFFA7D51FFF87D53FFFFC4B2FFAB4E00FFA94F00FFD1AB + B9FFCFA9B2FFD0A8B0FFD8A2A6FF49D0FFFF4FC9FFFF1B89E8FF1B89E8FF4FC9 + FFFF49D0FFFFD8A2A6FFD0A8B0FFCFA9B2FFD0ABBAFFB35400FF261580FF0000 + 9AFF000093FF000091FF00008DFF40AAEBFF5FDAFFFFF7FFFFFFF7FFFFFF5FDA + FFFF40AAEBFF00008DFF000091FF000093FF00009BFF402166FF090699FFABCD + FFFF4A81FFFF4B80FFFF4B7CFFFF084BBCFFFFFFFFFF1B9654FF1B9654FFFFFF + FFFF084BBCFF4B7CFFFF4B80FFFF4A81FFFFAACDFFFF07059AFF0C0796FFCCE9 + FFFFC6E0FFFFC3DBFFFFC1D3FFFFE7E4FFFF007E2DFF2AEECAFF2AEECAFF007E + 2DFFE7E4FFFFC1D3FFFFC3DBFFFFC6E0FFFFCCE9FFFF0B0796FF110D8FEF0B06 + 95FF070092FF020092FFE5CDF6FF008230FF11E3BFFF00D498FF00D499FF12E3 + BFFF008230FFE5CDF6FF020092FF070092FF0B0695FF0C0A6AB0000000000000 + 0000000000000000000000923CFF1BEAC8FF00CDA0FF00C99CFF00C99CFF00CD + A0FF1BEAC8FF00923CFF00000000000000000000000000000000000000000000 + 00000000000000000000006431AE008A47FF00843FFF4CD7C0FF00C39FFF0085 + 41FF008A47FF006431AE00000000000000000000000000000000000000000000 + 000000000000000000000000000000000000008843FF6FDED1FF00BEA1FF0089 + 45FF000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000008A46FF86E4DEFF88E5DFFF008A + 47FF000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000006134B0008A47FF008A47FF0061 + 34B0000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0023000000330000003300000033000000330000003300000033000000330000 + 0033000000330000003300000033000000230000000000000000000000002B48 + 66C0396592FF356291FF346191FF346191FF346192FF346293FF346293FF3462 + 93FF346293FF356292FF396593FF2B4866C00000000000000000000000003967 + 94FF96A8B1FFBEB9B1FFBAB6AFFFBAB6AFFFBBB7B3FFBCBBBAFFBDBCBEFFBDBC + BEFFBDBBBAFFC0BBB5FF97A8B2FF396794FF0000000000000000000000003665 + 95FFBEB9B1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFBFBAB2FF366595FF0000000000000000000000003665 + 95FFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFBBB6AFFF366595FF0000000000000000000000003668 + 96FFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFBAB5AEFF366896FF0000000000000000000000003769 + 97FFBAB5AEFFFFFFFFFFFFFFFFFFFCFBFBFFFCFBFBFFFFFFFFFFFCFBFBFFFCFB + FBFFFFFFFFFFFFFFFFFFBAB5AEFF376997FF000000000000000000000000386B + 9AFFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFBAB5AEFF386B9AFF000000000000000000000000396C + 9BFFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFBAB5AEFF396C9BFF000000000000000000000000396D + 9CFFBAB5AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFBAB5AFFF396D9CFF0000000000000000000000003A6F + 9EFFB9B5AEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFB9B5AEFF3A6F9EFF0000000000000000000000003B70 + 9FFFBAB4ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFBAB4ADFF3B709FFF0000000000000000000000003C73 + A0FFBCB6AEFFFFFFFFFFFFFFFFFF999592FF9B9895FF9B9895FF9B9895FF9995 + 92FFFFFFFFFFFFFFFFFFBCB6AEFF3C73A0FF0000000000000000000000004076 + A2FFC5CACFFFBCB7AFFFBBB7B1FF908B88FFCAC8C7FFC9C7C6FFCAC8C7FF908B + 88FFBBB7B1FFBCB7AFFFC5CACFFF4076A2FF0000000000000000000000003154 + 71B04278A4FF3E77A4FF3A76A7FF867F7AFFB8B5B5FFB5B3B3FFB8B5B5FF867F + 7AFF3A76A7FF3E77A4FF4278A4FF315471B00000000000000000000000000000 + 000000000000000000000000000000000000979796FF959595FF979796FF0000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000002E00000033000000330000 + 0033000000330000003300000033000000330000003300000030000000230000 + 003300000033000000330000003300000033ADA9A3ECB1B0AEFFAEAEABFFADAD + ABFFADADABFFADADABFFADADABFFAEAEABFFAFAFADFFA8A8A6F22C4866C04068 + 93FF3F6893FF406893FF3E6793FF335F8FFFBBB7B0FFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0B0ADFF3F6A94FF568A + B0FF4C82ABFF4D82ABFF4B81ABFF417BA8FFB9B4ADFFFFFFFFFFFDFDFDFFFFFF + FFFFFFFFFFFFFFFFFFFFFEFEFEFFFCFCFCFFFFFFFFFFAEAEABFF3F6A95FF6594 + BBFF4C83AEFF4E83AEFF4C82AEFF427DACFFB8B3ACFFFFFFFFFFFBFBFAFF8181 + 81FFB5B5B6FFB4B4B4FFB1B1B1FFF9F9F8FFFFFFFFFFADADABFF3F6B95FF74A1 + C3FF4F86B1FF5187B2FF4F86B2FF4581B0FFB8B2ABFFFFFFFFFFF6F6F5FFFBFB + FAFFFBFBFAFFF9F9F8FFF7F7F6FFF4F4F3FFFFFFFFFFADADABFF3F6B97FF82AB + CCFF5088B5FF528AB6FF5189B6FF4784B5FFB8B2ABFFFFFFFFFFF3F2F2FF8484 + 84FFB2B2B3FFF5F4F4FFAEAEAEFFF1F0F0FFFFFFFFFFADADABFF3E6C97FF91B6 + D5FF528BBAFF558CBBFF548CBBFF4B88BBFFB8B2ABFFFFFFFFFFEEEDEDFFF3F2 + F2FFF3F2F2FFF1F0F0FFF0EFEFFFEDEBEBFFFFFFFFFFADADABFF3E6D97FF9FC1 + DDFF538EBDFF5791BFFF5691BFFF4D8CBFFFB7B1AAFFFFFFFFFFE9E9E8FF8585 + 85FFB2B1B1FFB0AFAFFFAEADADFFE8E8E6FFFFFFFFFFAEAEABFF3E6E99FFACCA + E4FF5691C1FF5A93C3FF5993C3FF508FC3FFB8B2AAFFFFFFFFFFE3E2E0FFE6E5 + E4FFE7E5E4FFE6E5E4FFE4E3E2FFE2E1E0FFFFFFFFFFAEAEACFF3E6F9AFFB9D5 + EAFF5794C7FF5B97C8FF5B98C9FF5395CAFFBAB3ABFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFAFADFF3D709AFFC6DE + F0FF5797CCFF5A9ACFFF589AD1FF5398D2FF92AABEFFB5B2ADFFB2AFAAFFB2AE + A9FFB3B0ABFFB1AFACFFAFAEACFFAEAEACFFB0B0ADFF7C7C7AB03E729DFFD4E7 + F7FF569BD3FFADA096FFAA9F98FFA79E98FFA49E99FFA59D97FF4E98D5FFCCE4 + F8FF2F6A9AFF000000000000000000000000000000000000000042759FFFAFD2 + F2FFA9D0F3FF978E87FFCECAC8FFCBC8C6FFCDCAC8FF968D87FFA8D0F4FFADD1 + F2FF3D739EFF0000000000000000000000000000000000000000315471B04378 + A2FF3D77A4FF888079FFB9B6B6FFB7B5B5FFB9B6B6FF888079FF3D77A4FF4378 + A2FF315471B00000000000000000000000000000000000000000000000000000 + 00000000000000000000807F7EFF7E7E7EFF807F7EFF00000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 00230000003300000033000000330000003300000033462F1781A56F38ED5A3C + 21B3000000330000003300000033000000240000000600000006000000002B48 + 66C0396592FF356291FF346191FF346191FF346192FF6A6E71FF5A626AFF9A6F + 47FF346293FF356292FF396593FF27405BC71B1209671A120A6B000000003967 + 94FF96A8B1FFBEB9B1FFBAB6AFFFBAB6AFFFBBB7B3FFC2A78CFF9E856BFFB07B + 44FFBDBBBAFFC0BBB5FF8999A2FF63594FFF51361B975D3E22B6000000003665 + 95FFBEB9B1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF3ECFFDCAD78FFC883 + 38FFEFEFEFFFE3E3E3FFA8825BFF936C44FF150E0755764E28BC000000003665 + 95FFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD9F + 81FFB9B9B9FFD09F69FFCC8538FFB67F44FFAD7335E648301761000000003668 + 96FFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBEBEBFFA086 + 6DFF9E958EFFE09B4DFFBAB5AEFF366896FF0000000000000000000000003769 + 97FFBAB5AEFFFFFFFFFFFFFFFFFFFCFBFBFFFCFBFBFFF2F2F2FFADAEB0FFCC84 + 37FFB98B5EFFFFFFFFFFBAB5AEFF376997FF000000000000000000000000386B + 9AFFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFF1F1F1FFABABABFFD4D4D5FFC4BD + B5FFCACBCFFFFFFFFFFFBAB5AEFF386B9AFF000000000000000000000000396C + 9BFFBAB5AEFFFFFFFFFFFFFFFFFFFFFFFFFFB9B8B8FFD1D0CFFFE5E5E4FFCCCA + CAFFC7C6C6FFFFFFFFFFBAB5AEFF396C9BFF000000000000000000000000396D + 9CFFBAB5AFFFFFFFFFFFFFFFFFFFFFFFFFFFCAC9C8FFE6E5E5FFF9F9F9FFD7D5 + D4FFC1C0BEFFFFFFFFFFBAB5AFFF396D9CFF0000000000000000000000003A6F + 9EFFB9B5AEFFFFFFFFFFFFFFFFFFFFFFFFFFCDCCCAFFFBFBFBFFFFFFFFFFDDDB + DAFFC1C1BFFFFFFFFFFFB9B5AEFF3A6F9EFF0000000000000000000000003B70 + 9FFFBAB4ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9D7 + D7FFB5B3B1FFFFFFFFFFBAB4ADFF3B709FFF0000000000000000000000003C73 + A0FFBCB6AEFFFFFFFFFFFFFFFFFF999592FF9B9895FF9B9895FF9B9895FFB4B2 + B0FFFFFFFFFFFFFFFFFFBCB6AEFF3C73A0FF0000000000000000000000004076 + A2FFC5CACFFFBCB7AFFFBBB7B1FF908B88FFCAC8C7FFC9C7C6FFCAC8C7FF908B + 88FFBBB7B1FFBCB7AFFFC5CACFFF4076A2FF0000000000000000000000003154 + 71B04278A4FF3E77A4FF3A76A7FF867F7AFFB8B5B5FFB5B3B3FFB8B5B5FF867F + 7AFF3A76A7FF3E77A4FF4278A4FF315471B00000000000000000000000000000 + 000000000000000000000000000000000000979796FF959595FF979796FF0000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000002300000033000000230000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000006236C1008C4BFF006135C00000000000000000000000000000 + 0000000000000000000000000033000000330000003300000000000000000000 + 000000000000008B4AFF0CDCA5FF019F60FF0000003300000021000000000000 + 000000000000000000334780ACFF487FAAFF4880AAFF00000033000000300000 + 003300000033008947FF1DDBABFF049C60FF008C4AFF005E31B9000000330000 + 0033000000333C81B5FF729EC0FF1FADFFFF427D9AAE4490C5FF008447F2008A + 49FF008846FF008440FF2DDAB2FF059A5CFF008744FF008A46FF2D875CFF8C7C + 80FF807A78FF9D9691FFB0A49CFFA0C3D8FFB0ECFFFF3F90C6FF008B4AFF45E3 + C6FF42E0C1FF40DCBDFF3DD9B8FF3EDBBAFF41DEBFFF41E2C3FF008840FFFFE7 + EEFFBFB4B6FF817B7AFFBBB7B4FFF4ECE5FFBFDEEAFF3F92CAFF006033AF0F9F + 67FF0D9D63FF0A995EFF50DDC4FF19A774FF08975BFF0A9A5FFF00853FFF0085 + 3CFF49AC7FFFE1D7DAFF837E7CFFDED6CFFF358FCBFF00000000000000000000 + 0000008B47FF008741FF65E3D3FF0E985EFF3EDCBBFF3FDEBEFF3EE0C0FF39E0 + C2FF00813AFFFFEDD7FFB8B4B5FF918883FF0000000000000000000000000000 + 0000358A63FF008941FF79E9E3FF129A65FF51E0C7FF00823DFF00823FFF0080 + 3FFF4CA964FFFFE5A0FFECEBF0FF86827FFF0000000000000000000000000000 + 00009C898FFF1A9E64FF00863FFF00853FFF63E4D6FF00823EFFFFE9A4FFFFEB + A5FFFFE69FFFFBD88CFFF4F7FCFF868483FF0000000000000000000000000000 + 0000908889FFFFFFFFFFFFAC64FF008641FF73E9E4FF00813CFFFFE2AAFFFAD9 + 94FFF5D58FFFF1CD81FFF8FCFFFF898685FF0000000000000000000000000000 + 00008D8A89FFFDFCFFFFF1AE6EFF0C914FFF00813BFF48A770FFFFDFB4FFF2D3 + 9DFFEDC780FFEEC887FFF7F9FEFF8C8988FF0000000000000000000000000000 + 0000605E5DAAC9C9CBFFFBE5D3FFF1B072FFFFF2E3FFFFF0DEFFF8E2C3FFF1D3 + A6FFE7B96FFFF8ECDAFFC8C7C9FF605E5DAA0000000000000000000000000000 + 00000808070D908E8CFFF2F5F9FFFAE7D4FFE2A866FFE2AE6DFFE3B373FFE4B4 + 71FFFBECDAFFF1F5F8FF908E8CFF0808070D0000000000000000000000000000 + 0000000000001211111E9A9998FFCED0D1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFCED0D2FF92908EFF1211111E000000000000000000000000000000000000 + 000000000000000000000808080D656361A9959291FF959291FF959291FF9592 + 91FF656361A90808080D00000000000000000000000000000000} + end> + end + object imgIcons32: TcxImageList + Height = 32 + Width = 32 + FormatVersion = 1 + DesignInfo = 11534816 + ImageInfo = < + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0001000000060000000E00000014000000160000001600000016000000160000 + 001600000016000000140000000E000000060000000100000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000020000 + 000D0000001F000000320000003E000000420000004300000043000000430000 + 0043000000420000003E000000320000001F0000000D00000002000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000A0000 + 00272524216A757169C4A9A398F8AFA99DFFAEA99CFFAEA89CFFAEA89CFFAEA8 + 9CFFAFA99DFFA9A398F8757169C42524216A000000270000000A000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000134F4C + 4793B4ADA2FFC2BBB0FFD0C7BEFFDFD5CDFFE6DCD4FFEDE1DBFFEFE4DDFFE7DD + D6FFE1D6CFFFD1C9BFFFC3BCB1FFB4AEA2FF4F4C479300000013000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000016B2AC + 9FFFC7C0B6FFCFC7BEFFD5CCC3FFDBD2C9FFE2D8D0FFE9DDD7FFEBE0D9FFE3D9 + D2FFDDD3CBFFD6CEC5FFD1C9C0FFC9C2B9FFB1AB9FFF00000016000000000000 + 0001000000030000000500000005000000050000000500000005000000050000 + 000500000005000000050000000500000005000000050000000400000019B5AC + 9DFFC9C1B8FFCDC5BCFFD4CBC2FFDAD1C8FFE1D7CFFFE7DCD5FFEADFD8FFE2D8 + D1FFDCD2CAFFD5CDC4FFCFC7BEFFCAC3B9FFB1AB9FFF00000016000000050000 + 00120000001D0000001F0000001F0000001F0000001F0000001F0000001F0000 + 001F0000001F0000001F0000001F0000001F0000001F0000001E0000002CB9AC + 9AFFC9BFB6FFCBC3BAFFD2C9C0FFD8CFC5FFDFD5CDFFE9DFD8FFE9DDD6FFE0D6 + CFFFDAD0C8FFD3CBC2FFCEC6BDFFC9C2B7FFB0AA9EFF00000014000000100000 + 00320F212E6D0E1E2A6C0E1E2A6C0E1E2A6C0E1E2A6C0E1E2A6C0E1E2A6C0E1E + 2A6C0E1E2A6C0E1E2A6C0E1E2A6C0E1E2A6C0E1E2A6C0C1D276A08141D63BCAB + 98FFCBC2B7FFE3DDD4FFF5EFE9FFFFFBF4FFFEFAF3FFFDF9F2FFFDF9F2FFFDFA + F3FFFFFBF4FFF6F0E8FFE4DDD5FFCBC4BAFFB0AA9EFF0000001000000016418F + C4F24498D2FF4094D0FF3E92CEFF3E92CEFF3E92CEFF3E92CEFF3E92CEFF3E92 + CEFF3E92CEFF3E92CEFF3E92CEFF3E92CEFF3E92CEFF3D92CFFF3691D3FF84A0 + AEFFFDF3EBFFD7D0C8FFC6BEB6FFBEB5ABFFC2B9AFFFC7BCB4FFC8BEB5FFC3B9 + B1FFBFB6ACFFC7BFB7FFD8D1C9FFF9F5EDFF6F6B64B500000010000000164498 + D2FF3F93CFFFA8FBFFFF9AF4FFFF95F3FFFF95F3FFFF95F3FFFF95F3FFFF95F3 + FFFF95F3FFFF95F3FFFF95F3FFFF95F3FFFF95F3FFFF94F3FFFF90F6FFFFA7C6 + C3FFA5988CFFB6AEA3FFC8BFB6FFD8CFC7FFE3D9D1FFEADED8FFECE1DAFFE4DA + D3FFDAD1C9FFCAC1B8FFB8AFA6FFA49C92FF706C64B800000014000000164397 + D1FF5DB3DFFF82D3F2FF9AEFFFFF8AEAFFFF8BEAFFFF8BEAFFFF8BEAFFFF8BEA + FFFF8BEAFFFF8BEAFFFF8BEAFFFF8BEAFFFF8BEAFFFF8AEAFFFF87EFFFFFB7A5 + 94FFCAC0B6FFCEC7BDFFD5CCC3FFDAD1C8FFE1D7CFFFE8DCD6FFEADFD8FFE2D8 + D1FFDCD2CAFFD6CEC5FFD1C9C0FFCBC4BAFFB1AB9FFF00000016000000164195 + D0FF7CD3F2FF5FB2E0FFA5EFFFFF86E6FDFF87E5FDFF87E5FDFF87E5FDFF87E5 + FDFF87E5FDFF87E5FDFF87E5FDFF87E5FDFF87E5FDFF86E6FFFF82EAFFFFB5A5 + 94FFC8BEB5FFCBC3BAFFD2C8BFFFD8CEC5FFDFD5CDFFE9DED8FFE9DDD6FFE0D6 + CFFFDACFC7FFD3CBC2FFCEC6BDFFC9C2B8FFB0AB9EFF00000016000000164094 + D0FF96ECFEFF4096D1FFA6F0FFFF8FE6FEFF83E3FDFF84E3FDFF84E3FDFF84E3 + FDFF84E3FDFF84E3FDFF84E3FDFF84E3FDFF84E3FDFF83E4FFFF7FE8FFFFB5A4 + 94FFC8C0B6FFE1DBD2FFF3EDE6FFFDF9F2FFFCF8F1FFFBF7F0FFFBF7F0FFFCF8 + F1FFFDF8F2FFF4EEE6FFE2DBD3FFCAC3B9FFAFAA9DFF00000016000000163F93 + CFFFA6F6FFFF459DD5FF8EDCF7FF9CE9FFFF7FE1FCFF81E1FCFF81E1FCFF81E1 + FCFF81E1FCFF81E1FCFF81E1FCFF81E1FCFF81E1FCFF80E2FEFF7BE6FFFFB4A3 + 92FFFCF4EEFFEEE7DEFFE3DCD3FFDDD5CCFFDDD5CBFFDDD4CBFFDDD4CBFFDDD4 + CBFFDDD5CBFFE3DCD3FFEEE7DEFFFBF6EFFFAEA89CFF00000013000000163E92 + CFFFA6F5FFFF5FBBE6FF69BBE5FFAFEFFFFF7DE0FCFF7CDFFCFF7DDFFCFF7DDF + FCFF7DDFFCFF7DDFFCFF7DDFFCFF7DDFFCFF7DDFFCFF7CE0FEFF78E3FFFFB7A2 + 91FFE4D6CAFFE2D7CDFFE0D6CCFFDFD5CBFFDFD5CBFFDFD5CBFFDFD5CBFFDFD5 + CBFFDFD5CBFFDFD6CCFFE2D8CDFFE2D8CEFFAFA99DFF0000000A000000163E92 + CFFFA9F3FFFF76D7F6FF429BD5FFB0EEFFFF8BE2FBFF78DDFBFF7ADDFBFF7ADD + FBFF7ADDFBFF7ADDFBFF7ADDFBFF7ADDFBFF7ADDFBFF7ADDFCFF77E0FFFF91C6 + D2FFBDAB9AFFD6C7BAFFE3D8CDFFF0E6DBFFF0E6DBFFF0E6DBFFF0E6DBFFF0E6 + DBFFF0E6DBFFE3D8CDFFD5C9BBFFBAB0A1FF4E4A447A00000002000000163D92 + CEFFAAF2FFFF81E6FFFF3F96D0FF97DFF8FFA1E7FEFF72DAFAFF75DBFAFF76DB + FAFF76DBFAFF76DBFAFF76DBFAFF77DBFAFF77DBFAFF77DBFAFF76DCFCFF73DE + FFFF82D0E7FF9BBABCFFACABA0FFB5A392FFB4A392FFB4A392FFB4A392FFB4A3 + 92FFB4A392FFB4AEA1FF9EB1B6FF395363A20000001200000000000000163D92 + CEFFAEF0FFFF7EE4FFFF53ADDEFF73C4EBFFBCEFFEFF6CD8FAFF6ED8FAFF6FD8 + FAFF6FD8FAFF6FD9FAFF70D9FAFF73D9FAFF74D9FAFF74D9FAFF74D9FAFF73DA + FCFF71DBFDFF6FDCFFFF6EDDFFFF6DDDFFFF6DDDFFFF6DDDFFFF6DDDFFFF6DDD + FFFF6CDCFFFF82E3FFFFB5ECFFFF3582B9E70000001A00000002000000163D92 + CFFFB1F1FFFF7AE1FDFF68C7EFFF47A4DAFFC6F4FFFFC3F2FFFFC4F2FFFFC4F2 + FFFFC4F2FFFFC5F2FFFFC7F2FFFF70D8FBFF71D7FAFF71D6F9FF71D6F9FF71D6 + F9FF71D6F9FF71D6FAFF70D6FAFF70D7FAFF70D7FBFF70D7FBFF70D7FBFF70D7 + FBFF6FD6FAFF6BD6FBFFBCF1FFFF66ADDBFF0306092F00000008000000163D92 + CFFFB5F1FFFF77DDFCFF7CE0FEFF52ACDEFF378BCAFF368BCBFF368BCBFF368B + CBFF368BCBFF368BCBFF388BCBFF4FA9DDFF70D8FCFF6FD6FAFF6DD4F9FF6DD4 + F9FF6CD4F9FF6CD4F9FF6CD4F9FF6CD4F9FF6CD4F9FF6CD4F9FF6CD4F9FF6CD4 + F9FF6CD3F9FF68D2F9FFA1E7FDFF93CAE9FF1533477B00000010000000163D92 + CFFFB8F1FFFF74DBFAFF77DCFBFF7ADFFCFF7AE0FDFF7AE1FDFF7BE1FDFF7BE1 + FDFF7BE1FDFF7BE1FDFF7CE2FEFF54ACDEFF4FA8DDFF6AD5FBFF65D2F9FF63D0 + F8FF62D0F8FF62D0F8FF62D0F8FF62D0F8FF62D0F8FF62D0F8FF62D0F8FF62D0 + F8FF62D0F8FF60D0F8FF7FDBFBFFC8EDFBFF2C6B98CA00000013000000163C92 + CFFFBDF2FFFF71DAFAFF74DAFAFF75DBFAFF76DBFBFF76DBFBFF76DBFBFF76DB + FBFF76DBFBFF76DCFBFF77DCFCFF79DFFDFF52ACDEFF4AA6DDFFDAF9FFFFD6F7 + FFFFD5F6FFFFD5F6FFFFD5F6FFFFD5F6FFFFD5F6FFFFD5F6FFFFD5F6FFFFD5F7 + FFFFD5F7FFFFD5F7FFFFD4F7FFFFD9FCFFFF3D94D0FF0000000D000000163C92 + CFFFC0F3FFFF6ED8FAFF72D8FAFF73D8FAFF73D8FAFF73D8FAFF73D8FAFF73D8 + FAFF73D8FAFF73D8FAFF73D8FAFF74DAFBFF76DDFDFF51ABDDFF388CCBFF368C + CBFF368CCBFF368CCBFF368CCBFF368CCBFF368CCBFF368BCBFF358BCBFF358C + CCFF3890CEFF3A91CEFF3B92CFFF3D94D0FF2E6891B400000004000000163C92 + CFFFC4F3FFFF6CD6F9FF70D7F9FF71D7F9FF71D7F9FF71D7F9FF71D7F9FF71D7 + F9FF71D7F9FF71D7F9FF71D7F9FF71D7F9FF72D9FAFF73DAFBFF74DCFCFF74DC + FCFF74DCFCFF74DCFCFF74DCFCFF74DCFCFF74DCFCFF73DCFCFF70DCFDFFBDF3 + FFFF3D93CFFF0000001600000000000000000000000000000000000000163B92 + CFFFC9F5FFFF69D4F9FF6ED5F9FF6FD5F9FF6FD5F9FF6FD5F9FF6FD5F9FF6FD5 + F9FF6ED5F9FF6ED5F9FF6DD5F9FF6DD5F9FF6ED5F9FF6ED5F9FF6ED5FAFF6ED5 + FAFF6ED5FAFF6ED5FAFF6ED5FAFF6ED5FAFF6ED5FAFF6DD5FAFF69D5FAFFC7F5 + FFFF3C92CFFF0000001600000000000000000000000000000000000000163B92 + CFFFCFF5FFFF67D3F8FF6CD4F8FF6DD4F8FF6DD4F8FF6DD4F8FF6DD4F8FF6BD4 + F8FF68D3F8FF66D2F8FF66D2F8FF66D2F8FF66D2F8FF66D2F8FF66D2F8FF66D2 + F8FF66D2F8FF66D2F8FF66D2F8FF66D2F8FF66D2F8FF65D2F8FF62D2F9FFD5F7 + FFFF3B92CFFF0000001500000000000000000000000000000000000000163B92 + CFFFD3F6FFFF63D1F8FF68D2F8FF69D3F8FF69D3F8FF69D3F8FF69D2F8FF66D1 + F8FFA8E7FDFFDAF7FFFFDAF8FFFFDAF8FFFFDAF8FFFFDAF8FFFFDAF8FFFFDAF8 + FFFFDAF8FFFFDAF8FFFFDAF8FFFFDAF8FFFFDAF8FFFFDAF8FFFFD9F9FFFFDEFD + FFFF3D94D0FF0000000D00000000000000000000000000000000000000153B92 + CFFFD7F8FFFF5DCFF9FF60CFF8FF61CFF8FF61CFF8FF61CFF8FF61CFF8FF5ECF + F8FFBCEEFFFF348CCCFF3991CEFF3A92CFFF3A92CFFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3A92CFFF3A92CFFF3A92CFFF3A92CFFF3A92CFFF3A92CFFF3D94 + D0FF2E6891B400000004000000000000000000000000000000000000000D3D94 + D0FFDBFCFFFFD7F8FFFFD8F7FFFFD8F7FFFFD8F7FFFFD8F7FFFFD8F7FFFFD8F8 + FFFFDBFCFFFF3C93D0FF0000000D000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000042E68 + 91B43D94D0FF3B92CFFF3A92CFFF3A92CFFF3A92CFFF3A92CFFF3A92CFFF3B92 + CFFF3D94D0FF2E6890B300000004000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000050000001000000016000000160000001600000016000000160000 + 0016000000110000000800000004000000050000000B00000013000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 001600000016000000150000000D000000040000000000000000000000000000 + 00050000001A0000003500000042000000430000004300000043000000430000 + 00430000003A000000270000001E000000210000002D0000003C000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 0043000000430000003F0000002E000000150000000400000000000000000000 + 001000000035A87716F0B68116FFB68116FFB58013FFB37A06FFD9D2D2FFD7CD + C5FFD8CDC3FF2A29286931312F6A2F2F2D6A5D4F3696D9CFC8FFD7CCC4FFD7CC + C3FFD7CCC3FFD7CCC3FFD7CCC3FFD7CCC3FFD7CCC5FFD9D2D2FFB37A06FFB580 + 13FFB68116FFB68116FF7C5810C50000002E0000000D00000000000000000000 + 0016A87716EFF6CD89FFF3C883FFF2C782FFF2C680FFF0C173FFFFFFFFFFFFF3 + E9FFFFFFFFFF535352FF877E78FF877F79FF827A76FFFFFFFFFFFFF2E8FFFFF1 + E7FFFFF1E7FFFFF1E7FFFFF1E7FFFFF1E7FFFFF1E9FFFFFFFFFFF0C173FFF2C6 + 80FFF2C782FFF3C883FFF6CD89FF7B5810C10000001500000000000000000000 + 0016B68116FFF3C985FFEEC176FFEDC076FFECBF73FFEBBA68FFFFFFFFFFFBEE + E3FFFFFFFEFF575655FF8D847CFF8C837CFF847B74FFFFFFFDFFFBEEE2FFFAED + E1FFFAEDE1FFFAEDE1FFFAEDE1FFFAECE1FFF9ECE2FFFFFFFFFFEBBA68FFECBF + 73FFEDC076FFEEC176FFF3C985FFB68116FF0000001600000000000000000000 + 0016B68116FFF1C985FFECBD70FFEBBD70FFEBBC6EFFE9B763FFFEFFFFFFF9EA + DEFFFFFFFEFF545353FF8C837BFF8B817AFF827972FFFFFFFCFFF9EADEFFF7E9 + DEFFF7E9DEFFF7E9DEFFF7E9DEFFF7E9DEFFF7E8DEFFFEFFFFFFE9B763FFEBBC + 6EFFEBBD70FFECBD70FFF1C985FFB68116FF0000001600000000000000000000 + 0016B68116FFF1C986FFEABB6CFFEABB6CFFEABA6AFFE8B55EFFFDFEFFFFF7E8 + DBFFFFFFFCFF515050FF898078FF897E77FF80756EFFFFFFFAFFF7E8DBFFF5E7 + DBFFF5E7DBFFF5E7DBFFF5E7DBFFF5E7DBFFF5E7DBFFFDFEFFFFE8B55EFFEABA + 6AFFEABB6CFFEABB6CFFF1C986FFB68116FF0000001600000000000000000000 + 0016B68116FFF3C988FFEBB967FFEAB968FFEAB866FFE8B35AFFFCFDFFFFF3E4 + D8FFFFFFFBFF4D4C4DFF877D75FF857C74FF7D726BFFFFFEF9FFF3E4D8FFF2E4 + D8FFF2E4D8FFF2E4D8FFF2E4D8FFF2E4D8FFF1E3D8FFFDFDFFFFE8B35AFFEAB8 + 66FFEAB968FFEBB967FFF3C988FFB68116FF0000001600000000000000000000 + 0016B68116FFF1CB8AFFE9B763FFE9B764FFE9B662FFE7B156FFFCFCFFFFF1E2 + D6FFFFFFF8FF484748FF827871FF817871FF786E67FFFFFDF7FFF1E2D6FFF0E2 + D6FFF0E2D6FFF0E2D6FFF0E2D6FFF0E2D6FFEFE1D6FFFCFCFFFFE7B156FFE9B6 + 62FFE9B764FFE9B763FFF1CB8AFFB68116FF0000001600000000000000000000 + 0016B68116FFF2CB8BFFE8B55EFFE8B55FFFE8B45EFFE6AF52FFFCFCFFFFEEDE + D3FFFCF1E9FF87807BFF424446FF414346FF837E7AFFFCF1E9FFEFDFD3FFEEDE + D2FFEEDFD3FFEEDFD3FFEEDFD3FFEEDED2FFEDDED2FFFCFCFFFFE6AF52FFE8B4 + 5EFFE8B55FFFE8B55EFFF2CB8BFFB68116FF0000001600000000000000000000 + 0016B68116FFF3CB8EFFE7B25BFFE7B35DFFE7B25BFFE6AE50FFFBFCFFFFE9DC + D1FFEDDED1FFF3E3D6FFF7E8DAFFF7E8DAFFF2E3D6FFEDDED1FFEADCCFFFE9DC + CFFFE9DCCFFFE9DCCFFFE9DCCFFFE9DBCFFFE9DCD1FFFBFDFFFFE6AE50FFE7B2 + 5BFFE7B35DFFE7B25BFFF3CB8EFFB68116FF0000001600000000000000000000 + 0016B68116FFF3CC8FFFE7B056FFE7B158FFE7B158FFE7AE51FFE7CCA6FFFAFC + FFFFFAFAFFFFFBFBFFFFFCFCFFFFFCFCFFFFFBFBFFFFFAFAFFFFFAFAFFFFFAFA + FFFFFAFAFFFFFAFAFFFFFAFAFFFFFAFAFFFFFAFCFFFFE7CCA6FFE7AE51FFE7B1 + 58FFE7B158FFE7B056FFF3CC8FFFB68116FF0000001600000000000000000000 + 0016B68115FFF3CE92FFE6AE52FFE6AF54FFE6AF55FFE6AE52FFE5AC4DFFE5AA + 48FFE4A946FFE4A946FFE4A946FFE4A946FFE4A946FFE4A946FFE4A946FFE4A9 + 46FFE4A946FFE4A946FFE4A946FFE4A946FFE5AA48FFE5AC4DFFE6AE52FFE6AF + 55FFE6AF54FFE6AE52FFF3CE92FFB68115FF0000001600000000000000000000 + 0016B68115FFF3CF95FFE5AB4DFFE5AD50FFE5AD51FFE5AC4FFFE5AB4EFFE4AB + 4CFFE4AB4CFFE4AB4CFFE4AB4CFFE4AB4CFFE4AB4CFFE4AB4CFFE4AB4CFFE4AB + 4CFFE4AB4CFFE4AB4CFFE4AB4CFFE4AB4CFFE4AB4CFFE5AB4EFFE5AC4FFFE5AD + 51FFE5AD50FFE5AB4DFFF3CF95FFB68115FF0000001600000000000000000000 + 0016B68115FFF3D198FFE4A948FFE4AA4BFFE3A94AFFE2A643FFE1A43EFFE1A3 + 3CFFE1A33CFFE1A33CFFE1A33CFFE1A33CFFE1A33CFFE1A33CFFE1A33CFFE1A3 + 3CFFE1A33CFFE1A33CFFE1A33CFFE1A33CFFE1A33CFFE1A43EFFE2A643FFE3A9 + 4AFFE4AA4BFFE4A948FFF3D198FFB68115FF0000001600000000000000000000 + 0016B68115FFF3D19BFFE3A744FFE3A847FFE1A43FFFF6DEBAFFFFFFFFFFFFFE + FDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFE + FDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFEFDFFFFFFFFFFF6DEBAFFE1A4 + 3FFFE3A847FFE3A744FFF3D19BFFB68115FF0000001600000000000000000000 + 0016B68115FFF3D49FFFE3A63FFFE3A642FFE1A135FFFFFFFFFFFFF9F2FFFFF8 + EFFFFFF8EFFFFFF7EFFFFFF7EEFFFFF8EFFFFFF8EFFFFFF8EFFFFFF7EFFFFFF7 + EEFFFFF8EFFFFFF8EFFFFFF8EFFFFFF8EFFFFFF7EFFFFFF8F2FFFFFFFFFFE1A1 + 35FFE3A642FFE3A63FFFF3D49FFFB68115FF0000001600000000000000000000 + 0016B68115FFF5D5A2FFE2A33BFFE1A43DFFDF9E30FFFEFCFCFFFEF7EFFFFFFA + EFFFFFFAEFFFFFF9EEFFFFF8EEFFFFFBF1FFFFFCF2FFFFFBF0FFFFF9EEFFFFF8 + EDFFFFFAEFFFFFFBF0FFFFFAEFFFFFFAEFFFFFF8EEFFFEF6EEFFFEFBFBFFDF9E + 30FFE1A43DFFE2A33BFFF5D5A2FFB68115FF0000001600000000000000000000 + 0016B68114FFF5D6A6FFE1A136FFE0A239FFDE9C2BFFFCFBFBFFFFF9F0FF4E50 + 53FF909294FF8D8F91FFFFFBF1FF515255FF535557FF919395FF8D8F91FFFFFB + F0FF4F5153FF919295FF909294FF8F9193FF8C8D90FFFDF7EEFFFCFBFBFFDE9C + 2BFFE0A239FFE1A136FFF5D6A6FFB68114FF0000001600000000000000000000 + 0016B68014FFF6D9ABFFDF9F31FFDFA035FFDD9A27FFFBFAFAFFFCF6EDFFFFFA + EFFFFFFAEFFFFFF8EDFFFFF7EDFFFFFAF0FFFFFCF1FFFFFAEFFFFFF8EDFFFEF7 + ECFFFFFAEFFFFFFAF0FFFFFAEFFFFFF9EEFFFFF7ECFFFBF5ECFFFBFAFAFFDD9A + 27FFDFA035FFDF9F31FFF6D9ABFFB68014FF0000001600000000000000000000 + 0016B68014FFF6DCB1FFDF9C2DFFDF9E30FFDE9822FFF9F8F8FFFAF4EBFFFFF8 + EDFFFFFAEEFFFFF8EDFFFEF7ECFFFFF7ECFFFFF7ECFFFEF7ECFFFDF5EBFFFCF5 + EAFFFFF8EDFFFFFAEEFFFFF8EDFFFEF7ECFFFCF5EAFFF9F2EAFFF9F8F8FFDE98 + 22FFDF9E30FFDF9C2DFFF6DCB1FFB68014FF0000001600000000000000000000 + 0016B68014FFF8DDB4FFDE9A29FFDE9C2DFFDD961FFFF7F7F8FFFAF5ECFF5153 + 56FF555658FF939496FF919295FF919294FF919294FF909294FF8E8F92FFFEF7 + ECFF525356FF555658FF939496FF909294FF8D8F91FFF8F3EAFFF7F7F7FFDD96 + 1FFFDE9C2DFFDE9A29FFF8DDB4FFB68014FF0000001600000000000000000000 + 0016B68013FFF8E0BBFFDD9724FFDE9A29FFDC941BFFF6F5F5FFF7F1E8FFFCF5 + EAFFFFF7ECFFFDF5EAFFFCF4E9FFFBF4E8FFFBF4E8FFFBF4E8FFFAF2E8FFF9F2 + E7FFFCF5EAFFFEF6EBFFFDF5EAFFFCF4E9FFF9F2E7FFF6EFE7FFF6F5F5FFDC94 + 1BFFDE9A29FFDD9724FFF8E0BBFFB68013FF0000001600000000000000000000 + 0016B68013FFF9E2C0FFDD961FFFDF9925FFDC9217FFF4F4F5FFF5F0E7FFFAF4 + E9FFFCF6EAFFFAF4E9FFF9F3E7FFF8F1E7FFF7F1E6FFF9F3E8FFFAF3E8FFF9F2 + E7FFF8F1E7FFF7F1E7FFFAF3E9FFF9F3E8FFF7F1E6FFF4EEE6FFF4F4F5FFDC92 + 17FFDF9925FFDD961FFFF9E2C0FFB68013FF0000001600000000000000000000 + 0016B68012FFF9E5C5FFDF951BFFA97218FFDF9213FFF2F3F3FFF5F0E7FF5354 + 57FF565759FF949597FF929395FF8F9193FFF8F1E7FF515355FF939496FF9293 + 95FF8F9193FFF8F1E7FF515355FF929496FF8F9092FFF3EEE5FFF2F2F3FFDF92 + 13FFA97218FFDF951BFFF9E5C5FFB68012FF0000001600000000000000000000 + 0016B67F12FFFBE9CCFFE09417FF7E540EFFE0910FFFF1F2F3FFF1ECE4FFF6EF + E5FFF7F1E6FFF6F0E4FFF5EEE3FFF4EDE2FFF3EDE2FFF5EFE4FFF6EFE4FFF5EE + E3FFF4EDE2FFF3EDE2FFF5EFE4FFF5EFE4FFF3EDE2FFF0EBE3FFF1F1F2FFE091 + 0FFF7E540EFFE09417FFFBE9CCFFB67F12FF0000001600000000000000000000 + 0016B57F12FFFCECD1FFDE9010FF7B5008FFDE8E09FFEEF0F0FFEDE9E0FFEDE8 + DEFFEEE9DEFFEDE8DEFFEDE8DEFFEDE8DDFFECE8DDFFEDE8DEFFEDE8DEFFEDE8 + DEFFEDE8DDFFECE8DDFFEDE8DEFFEDE8DEFFEDE8DDFFECE9E0FFEEF0F0FFDE8E + 09FF7B5008FFDE9010FFFCECD1FFB57F12FF0000001500000000000000000000 + 0010B68013FFFDEED8FFD98904FFDB8C09FFD88600FFEDECECFFEBE6DEFFEBE5 + DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE5 + DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE5DCFFEBE6DEFFEDECECFFD886 + 00FFDB8C09FFD98904FFFDEED8FFB68013FF0000000D00000000000000000000 + 0005A87715EBF1C680FFFDECCFFFFDEBCEFFFCE8C6FFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE8 + C6FFFDEBCEFFFDECCFFFF1C680FF7C580FB30000000400000000000000000000 + 000000000005A77615EAB68013FFB57F12FFB57E10FFB57D0CFFB57C0AFFB57C + 09FFB57C09FFB57C09FFB57C09FFB57C09FFB57C09FFB57C09FFB57C09FFB57C + 09FFB57C09FFB57C09FFB57C09FFB57C09FFB57C09FFB57C0AFFB57D0CFFB57E + 10FFB57F12FFB68013FF7C580FB0000000040000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 00000000000000000000000000040000000D0000001500000016000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 0016000000160000001600000016000000150000000D00000004000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000D0000002B0000003F00000043000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 00430000004300000043000000430000003F0000002B0000000D000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000100000016906C3FC4CD9A58FFCD9957FFCD9957FFCD98 + 55FFCE964EFFAFB4BAFFB1B1B2FFB1B1B1FFB1B1B1FFB1B1B1FFB1B1B1FFB1B1 + B1FFB1B1B1FFB1B1B1FFB1B1B1FFB2B2B2FF7D7D7DC400000015000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00030000000B000000150000002AD19B55FFECDEBBFFE6D4AAFFE6D4A9FFE6D3 + A8FFE6D1A1FFFBFEFFFFFBFCFBFFFBFBFAFFFBFBFAFFFBFBFAFFFBFBFAFFFBFB + FAFFFBFBFAFFFBFBFAFFFCFCFBFFFFFFFFFFB3B3B4FF0000001C000000030000 + 0000000000000000000000000000000000000000000000000000000000040000 + 00130000002B0000003E16161666D19951FFEBDAB5FFE2C998FFE2C897FFE2C9 + 97FFE3C894FFF5F8FCFFF6F7F6FFF5F5F4FFF5F5F4FFF5F5F4FFF5F5F4FFF5F5 + F4FFF5F5F4FFF6F6F5FFF6F6F5FFFCFCFBFFB3B3B4FF000000320000001C0000 + 00150000000D00000004000000000000000000000000000000000000000D0000 + 002E4F4C46A8969188FF9E9C97FFD0984FFFEAD7B0FFFFFFFFFFFFFFFFFFFFFF + FFFFE1C38DFFF3F6FAFFAAAAAAFFD5D5D4FFF3F3F2FFBFBFBEFFD5D5D4FFD4D4 + D3FFF4F4F3FFAAAAA9FFD5D5D4FFFBFBFAFFB2B2B4FF45423CA1000000450000 + 003F0000002B0000000D00000000000000000000000000000000000000156764 + 5DC1A09B91FFC8C1B8FFD1CCC9FFCE964DFFEBD8B2FFDFC28CFFDFC18BFFE0C2 + 8CFFE0C289FFF1F4F8FFF3F4F3FFF3F3F2FFF2F2F1FFF2F2F1FFF2F2F1FFF3F3 + F2FFF2F3F2FFF3F3F2FFF2F2F1FFFAFAF9FFB0B0B1FFB2B3B4FFB2B2B2FFB2B2 + B2FF7D7D7DC40000001500000000000000000000000000000000000000169994 + 89FFC8C1B7FFCBC5BCFFCEC9C6FFCD954CFFECD8B3FFDEBF85FFDEBE85FFDEBF + 86FFDFBE83FFEFF1F5FFBBBCBCFFD2D0CFFFD1D0CFFFD0CFCEFFF0EFEEFFA8A8 + A7FFD2D1D0FFD1D0CFFFD0CFCEFFF8F8F7FFADADADFFFFFFFEFFFCFCFBFFFFFF + FFFFB2B2B2FF0000001600000000000000000000000000000000000000169993 + 89FFCAC2B9FFCAC4BAFFCDC8C5FFCC944BFFEBD8B3FFFFFFFFFFFFFFFFFFFFFF + FFFFDEBA7DFFEDEEF3FFEEEEEEFFEFEEEDFFEEEDECFFEDECEBFFEEEDECFFEFEE + EDFFEFEEEDFFEEEDECFFEDECEBFFF7F7F6FFADADADFFFBFBFAFFF7F7F6FFFCFC + FBFFB1B1B1FF0000002700000016000000150000000D00000004000000169A94 + 8AFFC9C1B8FFC9C3BAFFCCC8C4FFCC944BFFEDD9B7FFDCB97BFFDCB97BFFDDBA + 7DFFDDB97AFFEBEDF1FFB9B8B8FFCDCCCBFFCCCBCAFFEBEAE9FFB9B8B7FFCECD + CCFFCDCCCBFFCDCCCBFFCCCBCAFFF8F7F7FFAEAEAEFFAEAEADFFD6D6D5FFFBFB + FAFFB1B1B1FF00000048000000430000003F0000002B0000000D000000169A95 + 89FFC8C0B7FFC7C1B8FFD4D1CEFFCC934BFFEDDBB9FFDBB575FFDBB575FFDBB6 + 77FFDCB674FFE9EBF0FFEBEAEAFFEAE9E9FFE9E8E7FFE9E8E7FFEAE9E8FFEAE9 + E8FFEAE9E8FFEBEAE9FFE9E8E7FFF7F7F6FFAEAEAEFFF7F7F6FFF3F3F2FFFAFA + F9FFAFAFAFFFB1B1B2FFB1B1B1FFB2B2B2FF7D7D7DC400000015000000149A95 + 8AFFD3CCC3FFF6F1ECFFEEEDECFFCC934AFFEEDBB8FFFFFFFFFFFFFFFFFFFFFF + FFFFDBB16DFFE7E9EDFFA1A1A1FFCAC9C8FFE7E6E5FFB5B4B3FFCAC9C8FFC9C8 + C7FFE7E6E5FFA1A09FFFC9C8C7FFF7F7F6FFAEAEAEFFD4D3D2FFD1D0CFFFF8F8 + F7FFADADADFFFFFFFEFFFCFCFBFFFFFFFFFFB2B2B2FF00000016000000109B95 + 8BFFF2ECE4FFB7B0A8FFA39E99FFCD954CFFF0DEBEFFD8AD68FFD7AD68FFD9AE + 6AFFD9AE67FFE3E5E8FFE4E3E2FFE4E3E0FFE3E2E0FFE4E3E0FFE4E3E0FFE3E2 + E0FFE3E2E0FFE4E3E1FFE3E2E0FFF7F5F6FFADAEAEFFF1F0EFFFEEEDECFFF7F7 + F6FFADADADFFFBFBFAFFF7F7F6FFFCFCFBFFB1B1B1FF00000016000000106460 + 59B5B5ACA4FFB5ADA4FFC8C4C0FFCE964CFFF3E2C5FFF0DFC0FFF1DFC0FFF2DF + C0FFF2DDBAFFF4F7FBFFF4F5F5FFF5F5F3FFF6F6F3FFF6F6F4FFF5F5F4FFF5F5 + F4FFF5F5F4FFF5F5F4FFF5F5F4FFF8F7F7FFAEAEAEFFCFCECDFFCCCBCAFFF8F7 + F7FFAEAEAEFFAEAEADFFD6D6D5FFFBFBFAFFB1B1B1FF00000016000000146461 + 59B8B7AFA4FFCBC5BBFFCEC8C3FFCFA979FFCC944BFFCC944BFFCF964AFFD49A + 48FFD39641FFAEB1B1FFAEAEABFFB1B0ABFFB4B3ACFFB2B1AEFFB0B0AFFFAFAF + AFFFAEAEAFFFAFAFAFFFAFAFAFFFAFAFAFFFC5C6C6FFECEBEAFFEAE9E8FFF7F7 + F6FFAEAEAEFFF7F7F6FFF3F3F2FFFAFAF9FFB1B1B1FF0000001600000016A099 + 8FFFCAC2B9FFCAC3B9FFCDC6BEFFD0CAC4FFD4CECAFFD9D3CFFFE6DED2FF203B + DDFF8EA5FFFFFFFFFFFFFFFFFFFFFFFFFFFF294BF3FFF4F1E7FFA7A6A3FFCECD + CCFFEBE9E8FFB9B8B7FFCECCCBFFCCCBCAFFEAE9E8FFA2A1A0FFC9C8C7FFF7F7 + F6FFAEAEAEFFD4D3D2FFD1D0CFFFF9F9F8FFB1B1B1FF0000001600000016A09A + 8EFFC9C1B8FFC9C2B8FFCCC4BBFFCEC7BEFFD2C9C1FFD7CEC6FFE8DCC8FF273E + D3FFA0AFFBFF2B4AEDFF2C4BECFF2D4CEDFF2949EFFFF0EDDFFFE7E6E1FFE4E3 + E1FFE4E3E0FFE4E3E1FFE4E3E1FFE4E3E1FFE4E3E0FFE4E3E1FFE3E2E0FFF7F5 + F6FFADAEAEFFF1F0EFFFEEEDECFFF8F8F7FFB1B1B1FF0000001600000016A09A + 8FFFC8C0B7FFC7C0B6FFD4CDC4FFE4DDD6FFF2EDE5FFF8F2EAFFFFFFF5FF273D + D3FFA9B8FCFFA5B3F9FFA6B4FAFFA6B3FAFF9EACFBFFFFFEF2FFF6F6F3FFF5F4 + F4FFF6F5F4FFF6F5F4FFF5F5F4FFF5F5F4FFF5F5F4FFF5F5F4FFF5F5F4FFF8F7 + F7FFAEAEAEFFCFCECDFFCCCBCAFFF8F7F7FFB1B1B1FF0000001600000014A09A + 8EFFD3CBC3FFF6F1EAFFEFE9E3FFDAD5CDFFCAC2BAFFBEB4ABFFBDB2A1FF5E67 + BFFF283ED3FF2A3ED1FF2F3FD3FF353FD6FF2D38D5FFBAB3ACFFB1ACACFFB3AC + AEFFB8AEB0FFB4AFB0FFB0AFB0FFAFAFAFFFAEAEAFFFAFAFAFFFAFAFAFFFAFAF + AFFFC5C6C6FFECEBEAFFEAE9E8FFF7F7F6FFB1B1B1FF0000001600000010A29A + 8FFFF1EBE4FFB7AFA6FFA59C91FFABA298FFBBB2A9FFC5BBB1FFD4CBBFFFDDD1 + C0FFEDE0CCFFF8E9D5FFFFEFDDFF009E5AFF68E9C6FFFFFFFFFFFFFFFFFFFFFF + FFFF00BF8DFFF9EBEDFFA8A4A3FFCECDCCFFEBE9E8FFB9B8B7FFCECCCBFFCCCB + CAFFEAE9E8FFA2A1A0FFC9C8C7FFF7F7F6FFB1B1B1FF00000016000000106863 + 5CB5B4ACA3FFB5ADA2FFC9C1B8FFD3CBC2FFD6CDC4FFD9D0C8FFDDD3CBFFE0D7 + CEFFE5DAD0FFEBDED6FFFFE6E0FF00965FFF7CE5D1FF00BB8EFF00BA8EFF00BB + 90FF00BB8EFFF7E5E6FFE8E4E2FFE4E3E1FFE4E3E0FFE4E3E1FFE4E3E1FFE4E3 + E1FFE4E3E0FFE4E3E1FFE3E2E0FFF7F6F6FFB2B2B2FF00000015000000146964 + 5CB8B6AEA4FFCBC4BAFFCEC6BDFFD1C9C0FFD4CBC2FFD7CEC6FFDBD1C9FFDED5 + CDFFE2D8D0FFE8DCD6FFFEE3E0FF00945FFF8BE7DAFF86E4D5FF87E4D5FF86E4 + D5FF79E3D1FFFFF7FAFFF7F6F5FFF5F5F5FFF5F5F4FFF5F6F5FFF6F6F5FFF5F6 + F5FFF5F6F5FFF6F6F5FFF6F6F5FFFAF8F9FFB3B3B3FF0000000D00000016A59E + 93FFC9C1B9FFCAC3B9FFCDC5BCFFD0C8BFFFD4CBC2FFD7CEC6FFDBD1C9FFDED5 + CDFFE2D8D0FFE7DBD5FFF7E1DDFF45B290FF00945FFF009560FF009560FF0095 + 60FF00945DFFBAB1B4FFB1AFB1FFAFB0B1FFAFB0B1FFB1B1B2FFB2B2B3FFB2B2 + B2FFB2B2B2FFB1B1B2FFB2B2B2FFB3B3B3FF7D7D7DB40000000400000016A69F + 94FFC8C0B8FFC9C2B8FFCCC3BAFFCEC6BDFFD2C8BFFFD5CBC3FFD9CEC6FFDCD2 + CAFFE0D6CEFFE4D9D2FFEDDED8FFF7E1DDFFF9DFDBFFF7DCD7FFF2D8D4FFEED4 + CFFFE5D0CAFFDACCC3FFD2C8BEFFCEC5BBFFCBC2B8FFCAC1B6FFA49C8FFF0000 + 001600000000000000000000000000000000000000000000000000000016A7A0 + 93FFC7BEB6FFC6BFB4FFD2CBC2FFE2DBD3FFF0EAE2FFF3EEE7FFFDFAF3FFFDF9 + F2FFFDF8F2FFFCF8F1FFFDF8F1FFFEF8F2FFFFF9F3FFFFFAF3FFFFFAF4FFFFFA + F4FFF6EEE8FFF1EAE3FFE2DCD3FFD3CCC3FFC7BFB6FFC8BFB7FFA69E92FF0000 + 001600000000000000000000000000000000000000000000000000000016A69F + 93FFCFC8BFFFF8F4ECFFFFFAF4FFF8F2EBFFE9E2DAFFE3DAD3FFD7CFC6FFD4CB + C2FFD4CBC2FFD4CBC2FFD4CBC2FFD4CBC2FFD4CBC2FFD4CBC2FFD4CBC2FFD7CF + C6FFE3DAD3FFE9E2DAFFF8F2EBFFFFFAF4FFF4F0E8FFCFC8BFFFA69F92FF0000 + 001600000000000000000000000000000000000000000000000000000016A69E + 93FFFFFCF5FFEAE3DBFFD3C9C0FFCDC3B9FFCEC5BAFFCEC5BBFFCFC6BBFFCFC6 + BCFFCFC6BCFFCFC6BCFFCFC6BCFFCFC6BCFFCFC6BCFFCFC6BCFFCFC6BCFFCFC6 + BBFFCEC5BBFFCEC5BAFFCDC3B9FFD3C9C0FFEAE3DBFFFFFCF5FFABA499FF0000 + 001600000000000000000000000000000000000000000000000000000015A69F + 93FFECE5DDFFD5CCC2FFD5CCC2FFD6CDC3FFD7CEC3FFD7CEC4FFD7CEC4FFD7CE + C4FFD7CEC4FFD7CEC4FFD7CEC4FFD7CEC4FFD7CEC4FFD7CEC4FFD7CEC4FFD7CE + C4FFD7CEC4FFD7CEC3FFD6CDC3FFD5CCC2FFD5CCC2FFECE5DDFFA69F93FF0000 + 00150000000000000000000000000000000000000000000000000000000DA9A2 + 96FFE0D6CDFFE0D6CCFFDED5CBFFDDD4CAFFDDD4CAFFDDD4CAFFDDD4CAFFDDD4 + CAFFDDD4CAFFDDD4CAFFDDD4CAFFDDD4CAFFDDD4CAFFDDD4CAFFDDD4CAFFDDD4 + CAFFDDD4CAFFDDD4CAFFDDD4CAFFDED5CBFFDFD6CCFFE0D6CDFFA9A296FF0000 + 000D00000000000000000000000000000000000000000000000000000004746E + 67B2B5ADA1FFDED5CBFFE9E1D7FFE7DFD5FFE6DED4FFE5DDD3FFE5DDD3FFE4DC + D2FFE4DCD2FFE4DCD2FFE4DCD2FFE4DCD2FFE4DCD2FFE4DCD2FFE4DCD2FFE5DD + D3FFE5DDD3FFE6DED4FFE7DFD5FFE9E1D7FFE2DAD0FFB5ADA1FF746E67B20000 + 0004000000000000000000000000000000000000000000000000000000000000 + 00035A555089AAA396FFB7AEA3FFC8BFB4FFD9D1C6FFDDD5CAFFF1E9DFFFF0E8 + DEFFF0E8DEFFF0E8DEFFF0E8DEFFF0E8DEFFF0E8DEFFF0E8DEFFF0E8DEFFF1E9 + DFFFDDD5CAFFD9D1C6FFC8BFB4FFB7AEA3FFAAA296FF5A555089000000030000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000123211F3757534D858B857CD2968F84E2AAA296FFAAA2 + 96FFAAA296FFAAA296FFAAA296FFAAA296FFAAA296FFAAA296FFAAA296FFAAA2 + 96FF968F84E28B857CD257534D8523211F370000000100000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 00040000000D0000001500000016000000160000001600000016000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 00160000001600000016000000150000000D0000000400000000000000000000 + 000D0000002B0000003F00000043000000430000004300000043000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 004300000043000000430000003F0000002B0000000D00000000000000000000 + 0015004A22C400682EFF006730FF006731FF006832FF006832FF006832FF0068 + 32FF006832FF006930FF006E26FF0B31A7FF0B359BFF0B3598FF0B3598FF0B35 + 9BFF0B31A7FF006E26FF006930FF006832FF006832FF006832FF006832FF0068 + 32FF006731FF006730FF00682EFF004A22C40000001500000000000000000000 + 001600672DFF92DE9CFF1DAD36FF21AE3AFF23AF3AFF23AF3AFF23AF3AFF23AF + 3AFF23AF3AFF23B039FF24B830FF0B2EA6FF1075E1FF0A70DBFF0A70DBFF1075 + E1FF0B2EA6FF24B830FF23B039FF23AF3AFF23AF3AFF23AF3AFF23AF3AFF23AF + 3AFF21AE3AFF1DAD36FF92DE9CFF00672DFF0000001600000000000000000000 + 001600642AFF96E1A6FF2AB84AFF2FB84EFF30B950FF30B950FF30B950FF30B9 + 50FF30B950FF31BB4EFF33C546FF092DA6FF1C7AE1FF0B6ED9FF0B6ED9FF1C7A + E1FF092DA6FF33C546FF31BB4EFF30B950FF30B950FF30B950FF30B950FF30B9 + 50FF2FB84EFF2AB84AFF96E1A6FF00642AFF0000001600000000000000000000 + 0016006328FF9FEAB3FF38C660FF3CC663FF3DC664FF3DC664FF3DC664FF3DC6 + 64FF3DC664FF3EC863FF42D35CFF0A2DA6FF2781E1FF0D6FD8FF0D6FD8FF2781 + E1FF0A2DA6FF42D35CFF3EC863FF3DC664FF3DC664FF3DC664FF3DC664FF3DC6 + 64FF3CC663FF38C660FF9FEAB3FF006328FF0000001600000000000000000000 + 0016006328FFA6F4C0FF43D675FF45D577FF46D677FF46D677FF46D677FF46D6 + 77FF47D677FF4AD875FF51E26CFF082CA0FF3185E0FF0C6DD7FF0C6DD7FF3185 + E0FF082CA0FF51E26CFF4AD875FF47D677FF46D677FF46D677FF46D677FF46D6 + 77FF45D577FF43D675FFA6F4C0FF006328FF0000001600000000000000000000 + 001600662DFFA8FFD7FFA1FFD1FFA1FFD1FFA1FFD2FFA1FFD2FFA1FFD2FFA1FF + D2FFA2FFD0FFA9FFC8FF53C2F3FF22A2FFFF26A4FFFF27A5FFFF27A5FFFF26A4 + FFFF22A2FFFF53C2F3FFA9FFC8FFA2FFD0FFA1FFD2FFA1FFD2FFA1FFD2FFA1FF + D2FFA1FFD1FFA1FFD1FFA8FFD7FF00662DFF0000001600000000000000000000 + 00166F570EFFAE4300FFA74100FFA74100FFA74100FFA74100FFA74100FFA741 + 00FFA84100FFB33D00FF1EAAFFFF2BA9FFFF2EAAFFFF30ACFFFF30ACFFFF2EAA + FFFF2BA9FFFF1EAAFFFFB33D00FFA84100FFA74100FFA74100FFA74100FFA741 + 00FFA74100FFA74100FFAE4300FF6F570EFF0000001600000000000000000000 + 0016AA4C00FFFEB5A9FFEB6745FFEB6948FFEB6A49FFEB6A49FFEB6A49FFEB6A + 49FFED6946FFFB6435FF25B4FFFF34B2FFFF5197E1FF1073DAFF1073DAFF5197 + E1FF34B2FFFF25B4FFFFFB6435FFED6946FFEB6A49FFEB6A49FFEB6A49FFEB6A + 49FFEB6948FFEB6745FFFEB5A9FFAA4C00FF0000001600000000000000000000 + 0016A34B00FFFBC0AFFFEB7B54FFEB7E57FFEB7E58FFEB7E58FFEB7E58FFEB7E + 58FFED7D55FFFD7846FF2DBAFFFF3EBAFFFF1175DCFF157BDFFF157BDFFF1175 + DCFF3EBAFFFF2DBAFFFFFD7846FFED7D55FFEB7E58FFEB7E58FFEB7E58FFEB7E + 58FFEB7E57FFEB7B54FFFBC0AFFFA34B00FF0000001600000000000000000000 + 0016A24A00FFFFCAB8FFF28C63FFF18F65FFF18F66FFF18F66FFF18F66FFF18F + 66FFF48F64FFFF8B57FF35C1FFFF48C2FFFF1378DEFF177DE0FF177DE0FF1378 + DEFF48C2FFFF35C1FFFFFF8B57FFF48F64FFF18F66FFF18F66FFF18F66FFF18F + 66FFF18F65FFF28C63FFFFCAB8FFA24A00FF0000001600000000000000000000 + 0016A64C00FFFFDAC2FFFEA372FFFEA473FFFEA574FFFEA574FFFEA574FFFEA5 + 74FFFFA471FFFFA066FF40C6FFFF4FC7FFFF1278DFFF167DE1FF167DE1FF1278 + DFFF4FC7FFFF40C6FFFFFFA066FFFFA471FFFEA574FFFEA574FFFEA574FFFEA5 + 74FFFEA473FFFEA372FFFFDAC2FFA54B00FF0000001600000000000000000000 + 0016A94E00FFD2B1BEFFD0ADB5FFCFADB4FFCFAEB4FFCFAEB4FFCFAEB4FFCFAE + B4FFD1ADB3FFD8A6AAFF4DD1FFFF55CCFFFF72B8F1FF2490E9FF2490E9FF72B8 + F1FF55CCFFFF4DD1FFFFD8A6AAFFD1ADB3FFCFAEB4FFCFAEB4FFCFAEB4FFCFAE + B4FFCFADB4FFCFADB5FFD1B1BEFFB35200FF0000001600000000000000000000 + 00161C118AFF000099FF000092FF000091FF000091FF000091FF000091FF0000 + 91FF000090FF00008AFF5FDEFFFF5ED3FFFF5FD2FFFF61D3FFFF61D3FFFF5FD2 + FFFF5ED3FFFF5FDEFFFF00008AFF000090FF000091FF000091FF000091FF0000 + 91FF000091FF000092FF00009AFF341D68F40000001600000000000000000000 + 00160A0697FFA1C4FFFF3D75FFFF4076FFFF4177FFFF4177FFFF4177FFFF4177 + FFFF4076FFFF3E6FFFFF5BB7FFFF6AE2FFFF68DDFFFF6BDDFFFF6BDDFFFF68DD + FFFF6AE2FFFF5BB7FFFF3E6FFFFF4076FFFF4177FFFF4177FFFF4177FFFF4177 + FFFF4076FFFF3D75FFFFA1C4FFFF080599FF0000001600000000000000000000 + 00160A0493FFAAC7FFFF4D7DFFFF507FFFFF517FFFFF517FFFFF517FFFFF517F + FFFF517EFFFF507CFFFF5179FFFF0E4DB4FF96C8F5FF1080E6FF1080E6FF96C8 + F5FF0E4DB4FF5179FFFF507CFFFF517EFFFF517FFFFF517FFFFF517FFFFF517F + FFFF507FFFFF4D7DFFFFAAC7FFFF0A0493FF0000001600000000000000000000 + 0016090292FFB3CEFFFF5C89FFFF5F8AFDFF608AFDFF608AFDFF608AFDFF5F89 + FDFF5C88FDFF5B87FFFF5D88FFFF0850BCFF9ACFFBFF0D85ECFF0D85ECFF9ACF + FBFF0850BCFF5D88FFFF5B87FFFF5C88FDFF5F89FDFF608AFDFF608AFDFF608A + FDFF5F8AFDFF5C89FFFFB3CEFFFF090292FF0000001600000000000000000000 + 0016080292FFBED8FFFF6B97FFFF6D97FEFF6D98FEFF6D98FEFF6D97FEFF6A95 + FEFFA2BDFFFFC4DAFFFFC4DBFFFF93BAF3FFDEFAFFFF95D4FFFF95D4FFFFDEFA + FFFF93BAF3FFC4DBFFFFC4DAFFFFA2BDFFFF6A95FEFF6D97FEFF6D98FEFF6D98 + FEFF6D97FEFF6B97FFFFBED8FFFF080292FF0000001500000000000000000000 + 00100B0694FFD1EBFFFFCAE1FFFFCAE0FFFFCAE0FFFFCAE0FFFFC8E0FFFFC3DB + FFFFEEFCFFFFB79B7EFFBA7B2BFFB97B2FFFB8792FFFB97A2FFFB97A2FFFB879 + 2FFFB97B2FFFBA7B2BFFB79B7EFFEEFCFFFFC3DBFFFFC8E0FFFFCAE0FFFFCAE0 + FFFFCAE0FFFFCAE1FFFFD1EBFFFF0B0694FF0000000D00000000000000000000 + 0005100D8FF00B0595FF070292FF060192FF060192FF060092FF030092FF0000 + 91FF8C8DDBFFBB7F2FFFFECF86FFFACD87FFF9CC87FFFACC87FFFACC87FFF9CC + 87FFFACD87FFFECF86FFBB7F2FFF8C8DDBFF000091FF030092FF060092FF0601 + 92FF060192FF070292FF0B0595FF0C0A69B40000000400000000000000000000 + 00000000000000000000000000000000000000000000000000040000000D0000 + 001500000027BA8136FFF8CF91FFF1C076FFF0C076FFF0C076FFF0C076FFF0C0 + 76FFF1C076FFF8CF91FFBA8136FF00000027000000150000000D000000040000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000D0000002B0000 + 004000000048B7803BFFF4D099FFEAB96EFFEAB970FFEAB970FFEAB970FFEAB9 + 70FFEAB96EFFF4D099FFB7803BFF000000480000003F0000002B0000000D0000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000F86612EC2BA84 + 3FFFB6803DFFB37C3AFFF1D2A2FFE4B167FFE4B36AFFE4B36AFFE4B36AFFE4B3 + 6AFFE4B167FFF1D2A2FFB37C3AFFB7803DFFBB8440FF87612EC20000000F0000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000006B98442FFFBE2 + ACFFF7DDA7FFF5DBA6FFECC88AFFDFAB60FFDFAD63FFDFAD63FFDFAD63FFDFAD + 63FFDFAB60FFECC88AFFF6DCA6FFF8DEA7FFE0CDA1F7BA8442FF000000060000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000006B57F + 3EFFF4DAA7FFD9A455FFD9A558FFDAA75BFFDAA85DFFDAA85DFFDAA85DFFDAA8 + 5DFFDAA75BFFD9A558FFD9A455FFD6C399F2B6803EFF00000006000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0006B57F3EFFF2DAABFFD49F51FFD4A054FFD5A256FFD5A257FFD5A257FFD5A2 + 56FFD4A054FFD49F51FFEFD8ABFFB67F3EFF0000000600000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000006B6803FFFEFD9AEFFCD984BFFCE9A4EFFCF9C50FFCF9C50FFCE9A + 4EFFCD984BFFEDD8AFFFB6803FFF000000060000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000006B6803FFFEDD7B1FFC89242FFC99446FFC99446FFC892 + 42FFEED7B1FFB6803FFF00000006000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000006B7813FFFEBD7B4FFC28B39FFC28B39FFEBD7 + B4FFB7813FFF0000000600000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000006B7813FFFE9D7B8FFE9D7B8FFB781 + 3FFF000000060000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000006B88341FFB88341FF0000 + 0006000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 00040000000D0000001500000016000000160000001600000016000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 00160000001600000016000000150000000D0000000400000000000000000000 + 000D0000002B0000003F00000043000000430000004300000043000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 004300000043000000430000003F0000002B0000000D00000000000000000000 + 0015004A22C400682EFF006730FF006731FF006832FF006832FF006832FF0068 + 32FF006832FF006930FF006E26FF0B31A7FF0B359BFF0B3598FF0B3598FF0B35 + 9BFF0B31A7FF006E26FF006930FF006832FF006832FF006832FF006832FF0068 + 32FF006731FF006730FF00682EFF004A22C40000001500000000000000000000 + 001600672DFF92DE9CFF1DAD36FF21AE3AFF23AF3AFF23AF3AFF23AF3AFF23AF + 3AFF23AF3AFF23B039FF24B830FF0B2EA6FF1075E1FF0A70DBFF0A70DBFF1075 + E1FF0B2EA6FF24B830FF23B039FF23AF3AFF23AF3AFF23AF3AFF23AF3AFF23AF + 3AFF21AE3AFF1DAD36FF92DE9CFF00672DFF0000001600000000000000000000 + 001600642AFF96E1A6FF2AB84AFF2FB84EFF30B950FF30B950FF30B950FF30B9 + 50FF30B950FF31BB4EFF33C546FF092DA6FF1C7AE1FF0B6ED9FF0B6ED9FF1C7A + E1FF092DA6FF33C546FF31BB4EFF30B950FF30B950FF30B950FF30B950FF30B9 + 50FF2FB84EFF2AB84AFF96E1A6FF00642AFF0000001600000000000000000000 + 0016006328FF9FEAB3FF38C660FF3CC663FF3DC664FF3DC664FF3DC664FF3DC6 + 64FF3DC664FF3EC863FF42D35CFF0A2DA6FF2781E1FF0D6FD8FF0D6FD8FF2781 + E1FF0A2DA6FF42D35CFF3EC863FF3DC664FF3DC664FF3DC664FF3DC664FF3DC6 + 64FF3CC663FF38C660FF9FEAB3FF006328FF0000001600000000000000000000 + 0016006328FFA6F4C0FF43D675FF45D577FF46D677FF46D677FF46D677FF46D6 + 77FF47D677FF4AD875FF51E26CFF082CA0FF3185E0FF0C6DD7FF0C6DD7FF3185 + E0FF082CA0FF51E26CFF4AD875FF47D677FF46D677FF46D677FF46D677FF46D6 + 77FF45D577FF43D675FFA6F4C0FF006328FF0000001600000000000000000000 + 001600662DFFA8FFD7FFA1FFD1FFA1FFD1FFA1FFD2FFA1FFD2FFA1FFD2FFA1FF + D2FFA2FFD0FFA9FFC8FF53C2F3FF22A2FFFF26A4FFFF27A5FFFF27A5FFFF26A4 + FFFF22A2FFFF53C2F3FFA9FFC8FFA2FFD0FFA1FFD2FFA1FFD2FFA1FFD2FFA1FF + D2FFA1FFD1FFA1FFD1FFA8FFD7FF00662DFF0000001600000000000000000000 + 00166F570EFFAE4300FFA74100FFA74100FFA74100FFA74100FFA74100FFA741 + 00FFA84100FFB33D00FF1EAAFFFF2BA9FFFF2EAAFFFF30ACFFFF30ACFFFF2EAA + FFFF2BA9FFFF1EAAFFFFB33D00FFA84100FFA74100FFA74100FFA74100FFA741 + 00FFA74100FFA74100FFAE4300FF6F570EFF0000001600000000000000000000 + 0016AA4C00FFFEB5A9FFEB6745FFEB6948FFEB6A49FFEB6A49FFEB6A49FFEB6A + 49FFED6946FFFB6435FF25B4FFFF34B2FFFF5197E1FF1073DAFF1073DAFF5197 + E1FF34B2FFFF25B4FFFFFB6435FFED6946FFEB6A49FFEB6A49FFEB6A49FFEB6A + 49FFEB6948FFEB6745FFFEB5A9FFAA4C00FF0000001600000000000000000000 + 0016A34B00FFFBC0AFFFEB7B54FFEB7E57FFEB7E58FFEB7E58FFEB7E58FFEB7E + 58FFED7D55FFFD7846FF2DBAFFFF3EBAFFFF1175DCFF157BDFFF157BDFFF1175 + DCFF3EBAFFFF2DBAFFFFFD7846FFED7D55FFEB7E58FFEB7E58FFEB7E58FFEB7E + 58FFEB7E57FFEB7B54FFFBC0AFFFA34B00FF0000001600000000000000000000 + 0016A24A00FFFFCAB8FFF28C63FFF18F65FFF18F66FFF18F66FFF18F66FFF18F + 66FFF48F64FFFF8B57FF35C1FFFF48C2FFFF1378DEFF177DE0FF177DE0FF1378 + DEFF48C2FFFF35C1FFFFFF8B57FFF48F64FFF18F66FFF18F66FFF18F66FFF18F + 66FFF18F65FFF28C63FFFFCAB8FFA24A00FF0000001600000000000000000000 + 0016A64C00FFFFDAC2FFFEA372FFFEA473FFFEA574FFFEA574FFFEA574FFFEA5 + 74FFFFA471FFFFA066FF40C6FFFF4FC7FFFF1278DFFF167DE1FF167DE1FF1278 + DFFF4FC7FFFF40C6FFFFFFA066FFFFA471FFFEA574FFFEA574FFFEA574FFFEA5 + 74FFFEA473FFFEA372FFFFDAC2FFA54B00FF0000001600000000000000000000 + 0016A94E00FFD2B1BEFFD0ADB5FFCFADB4FFCFAEB4FFCFAEB4FFCFAEB4FFCFAE + B4FFD1ADB3FFD8A6AAFF4DD1FFFF55CCFFFF72B8F1FF2490E9FF2490E9FF72B8 + F1FF55CCFFFF4DD1FFFFD8A6AAFFD1ADB3FFCFAEB4FFCFAEB4FFCFAEB4FFCFAE + B4FFCFADB4FFCFADB5FFD1B1BEFFB35200FF0000001600000000000000000000 + 00161C118AFF000099FF000092FF000091FF000091FF000091FF000091FF0000 + 91FF000090FF00008AFF5FDEFFFF5ED3FFFF5FD2FFFF61D3FFFF61D3FFFF5FD2 + FFFF5ED3FFFF5FDEFFFF00008AFF000090FF000091FF000091FF000091FF0000 + 91FF000091FF000092FF00009AFF341D68F40000001600000000000000000000 + 00160A0697FFA1C4FFFF3D75FFFF4076FFFF4177FFFF4177FFFF4177FFFF4177 + FFFF4076FFFF3E6FFFFF5BB7FFFF6AE2FFFF68DDFFFF6BDDFFFF6BDDFFFF68DD + FFFF6AE2FFFF5BB7FFFF3E6FFFFF4076FFFF4177FFFF4177FFFF4177FFFF4177 + FFFF4076FFFF3D75FFFFA1C4FFFF080599FF0000001600000000000000000000 + 00160A0493FFAAC7FFFF4D7DFFFF507FFFFF517FFFFF517FFFFF517FFFFF517F + FFFF517FFFFF517DFFFF527AFFFF104EB5FF97C8F5FF107FE6FF107FE6FF97C8 + F5FF104EB5FF527AFFFF517DFFFF517FFFFF517FFFFF517FFFFF517FFFFF517F + FFFF507FFFFF4D7DFFFFAAC7FFFF0A0493FF0000001600000000000000000000 + 0016090292FFB3CEFFFF5C89FFFF5F8AFDFF608AFDFF608AFDFF608AFDFF608A + FDFF608AFDFF618BFEFF658CFFFF1055BBFF9FD1FAFF0D84EBFF0D84EBFF9FD1 + FAFF1055BBFF658CFFFF618BFEFF608AFDFF608AFDFF608AFDFF608AFDFF608A + FDFF5F8AFDFF5C89FFFFB3CEFFFF090292FF0000001600000000000000000000 + 0016080292FFBED8FFFF6B97FFFF6D97FEFF6D98FEFF6D98FEFF6D98FEFF6D98 + FEFF6D98FEFF6E98FEFF739BFFFF0E56C0FFA3D5FFFFDEEEFFFFDEEEFFFFA3D5 + FFFF0E56C0FF739BFFFF6E98FEFF6D98FEFF6D98FEFF6D98FEFF6D98FEFF6D98 + FEFF6D97FEFF6B97FFFFBED8FFFF080292FF0000001500000000000000000000 + 00100B0694FFD1EBFFFFCAE1FFFFCAE0FFFFCAE0FFFFCAE0FFFFCAE0FFFFCAE0 + FFFFCAE0FFFFCAE0FFFFCDE0FFFF0D58C8FFFFFFFFFF1E9755FF1E9755FFFFFF + FFFF0D58C8FFCDE0FFFFCAE0FFFFCAE0FFFFCAE0FFFFCAE0FFFFCAE0FFFFCAE0 + FFFFCAE0FFFFCAE1FFFFD1EBFFFF0B0694FF0000000D00000000000000000000 + 0005100D8FF00B0595FF070292FF060192FF070192FF070192FF070192FF0701 + 92FF070092FF060093FF040093FFF1EFFFFF007F2FFF00F0B6FF00F0B6FF007F + 2FFFF1EFFFFF040093FF060093FF070092FF070192FF070192FF070192FF0701 + 92FF060192FF070292FF0B0595FF0C0A69B40000000400000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000060000001C0000003D008A35FF00F2B8FF00DB99FF00DB99FF00F2 + B8FF008A35FF0000003D0000001C000000060000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00060000001C0000003D008F3CFF04F2BCFF00D79AFF00D59AFF00D59AFF00D8 + 9AFF04F2BCFF008F3CFF0000003D0000001C0000000600000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000060000 + 001C0000003D008A40FF0EEDC1FF00D39BFF00D19AFF00D19AFF00D19AFF00D1 + 9AFF00D49BFF0FE5BAFE008B40FF0000003C0000001B00000006000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000060000001C0000 + 003D008741FF18EAC3FF00D09BFF00CE9AFF00CE9AFF00CE9AFF00CE9AFF00CE + 9AFF00CE9AFF00D09BFF18E3BEFE008842FF0000003B0000001B000000060000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000F000000340087 + 43FF1FE6C4FF00CB9AFF00C998FF00CA99FF00CA9AFF00CA9AFF00CA9AFF00CA + 9AFF00CA99FF00CA98FF00CC9AFF1FBFA5ED008844FF000000330000000F0000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000D008C4AFF29E8 + CEFF27E2C6FF26DEC1FF16D4B1FF00C59AFF00C69BFF00C69BFF00C69BFF00C6 + 9BFF00C59AFF16D4B1FF26DFC1FF27E3C6FF2AC9B4EE008C4AFF0000000D0000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000004006235B6008A + 48FF008744FF00833DFF5CDBC5FF00C199FF00C29BFF00C29BFF00C29BFF00C2 + 9BFF00C199FF5CDBC5FF00833DFF008744FF008A48FF006235B6000000040000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000016008742FF7DE2D4FF00BC98FF00BD99FF00BD9AFF00BD9AFF00BD + 99FF00BC98FF7DE2D4FF008742FF000000160000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000015008743FF9DEAE2FF00B797FF00B898FF00B898FF00B898FF00B8 + 98FF00B797FF9DEAE2FF008743FF000000150000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000D008945FFB5F1F1FFB2EEEBFFB4EEEAFFB5EEEBFFB5EEEBFFB4EE + EAFFB2EEEBFFB5F1F1FF008945FF0000000D0000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000004006134B4008945FF008742FF008742FF008742FF008742FF0087 + 42FF008742FF008945FF006134B4000000040000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000050000001000000016000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 0016000000160000001600000016000000150000000D00000004000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000100000003100000042000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 00430000004300000043000000430000003F0000002B0000000D000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000016A39284F3AB9787FFAA9584FFAB95 + 83FFAB9583FFAA9584FFA99584FFA99585FFA99585FFA99585FFA99585FFA995 + 85FFA99585FFA99585FFA99585FFAA9787FF786B61C400000015000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000016AB9787FFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA9787FF00000016000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000016AA9584FFFFFFFFFF27D2FFFF32D3 + FFFF32D3FFFF26D2FFFFFFFFFFFFBEA07FFFBEA383FFBEA384FFBEA384FFBEA3 + 84FFBEA384FFBEA383FFBCA080FFFFFFFFFFA89584FF00000016000000000000 + 000000000000000000000000000000000000000000040000000D000000150000 + 001600000016000000160000001600000027AB9583FFFFFFFFFF27C2FFFF36C5 + FFFF36C6FFFF26C2FFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA89484FF00000016000000000000 + 0000000000000000000000000000000000000000000D0000002B0000003F0000 + 004300000043000000430000004300000048AB9583FFFFFFFFFF20B4FFFF31B9 + FFFF31B9FFFF20B5FFFFFFFEF8FFBFA180FFBEA385FFBFA485FFBFA485FFBFA4 + 85FFBFA485FFBEA384FFBCA081FFFFFFFFFFA89584FF00000016000000000000 + 00000000000000000000000000000000000000000015786B61C4AA9787FFA895 + 84FFA89483FFA89483FFA89584FFA99585FFA99280FFFFFFFFFF13A4FFFF24A9 + FFFF24AAFFFF14A4FFFFFFFBF4FFFBFAFCFFF9FCFFFFFAFCFFFFFAFCFFFFFAFC + FFFFFAFCFFFFF9FCFFFFF7F9FDFFFFFFFFFFA89584FF00000016000000000000 + 00000000000000000000000000000000000000000016AA9787FFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA58E7CFFFFFFFFFF008FFFFF0A94 + FFFF0A94FFFF0090FFFFFFF7F3FFC0A282FFBFA486FFBFA587FFBFA587FFBFA5 + 87FFBFA587FFBFA486FFBDA182FFFFFFFFFFA89584FF00000016000000050000 + 00100000001600000016000000160000001600000027A89584FFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA38D7CFFFFFFFFFFFBF4F3FFFFF8 + F6FFFFF8F6FFFCF7F7FFF3F4FAFFF0F5FEFFF0F6FFFFF0F6FFFFF0F6FFFFF0F6 + FFFFF0F6FFFFEFF5FFFFEEF3FAFFFFFFFFFFA89584FF00000016000000100000 + 00310000004200000043000000430000004300000048A89484FFFFFFFFFFBB9F + 7FFFBDA182FFBDA283FFBEA383FFC1A687FFA38F7FFFFFFFFFFFEAAE59FFECB3 + 61FFEDB463FFECB463FFEBB364FFEAB365FFEAB465FFEAB465FFEAB465FFEAB4 + 65FFEAB465FFEAB363FFE8AE5AFFFFFFFFFFA89585FF0000001600000016A392 + 84F3AA9787FFA89586FFA89586FFA99686FFA99687FFA69281FFFFFFFFFFFDFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA38F7FFFFFFFFFFFD39A46FFD5A0 + 51FFD6A154FFD6A154FFD6A154FFD6A154FFD6A154FFD6A154FFD6A154FFD6A1 + 54FFD6A154FFD5A051FFD39A46FFFFFFFFFFA89586FF0000001600000016AA97 + 87FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA39081FFFFFFFFFFBCA0 + 81FFBEA385FFBEA386FFBFA486FFC2A788FFA39080FFFFFFFFFFBE7E25FFC083 + 2FFFC18531FFC18531FFC18531FFC18531FFC18531FFC18531FFC18531FFC185 + 31FFC18531FFC0832FFFBE7E25FFFFFFFFFFA89586FF0000001500000016A895 + 86FFFFFFFFFFC98B34FFCE9440FFD39A47FFD99F47FFA39186FFFFFFFFFFF6FB + FFFFF8FDFFFFF8FEFFFFF9FEFFFFFCFFFFFFA39081FFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA9787FF0000000D00000016A895 + 86FFFFFFFFFFCA903DFFD09B4DFFD59F53FFDBA351FFA4948AFFFFFFFFFFEBB1 + 5CFFECB565FFEDB565FFEDB35FFFF0F6FEFFBF9F77FFA4958BFFA4958BFFA495 + 8BFFA4958BFFA4958BFFA4948BFFA39388FFA39185FFA39388FFA4948BFFA494 + 8AFFA39287FFA39182FFA79383FFAA9787FF776A60B30000000400000016A895 + 86FFFFFFFFFFCA923EFFD19C51FFD5A155FFDAA352FFA4958CFFFFFFFFFFDCA3 + 51FFDEA95CFFDEA95DFFDDA553FFF3FDFFFFE0A652FFE2AB5BFFE3AD5CFFE3AD + 5CFFE3AD5CFFE3AD5CFFE3AB5BFFE2A853FFF7FFFFFFE2A853FFE3AB5BFFE3AB + 5AFFE1A751FFFFFFFFFFA99687FF00000016000000000000000000000016A895 + 86FFFFFFFFFFCA913DFFD09C51FFD5A156FFD9A250FFA5958CFFFFFFFFFFCE94 + 3FFFD19B4CFFD19B4DFFCF9642FFF1FBFFFFD09642FFD29C4CFFD29D4FFFD29D + 4FFFD29D4FFFD29D4FFFD29C4CFFD09642FFF2FBFFFFD09642FFD29C4CFFD29B + 4CFFCF9540FFFFFFFFFFA99686FF00000016000000000000000000000016A896 + 86FFFFFFFFFFC98E3CFFCF9A4FFFD5A157FFD9A453FFA5958BFFFFFFFFFFBE7F + 24FFC1842FFFC2852FFFC08027FFF1F6FFFFC08027FFC2852FFFC28631FFC286 + 31FFC28631FFC28631FFC2852FFFC08027FFF1F6FFFFC08027FFC2852FFFC184 + 2FFFBE7F24FFFFFFFFFFA89586FF00000016000000000000000000000016A896 + 86FFFFFFFFFFC78D3BFFCE994DFFD39F54FFD8A354FFA5948AFFFFFFFFFFF4F0 + F7FFF9F3FEFFFAF4FEFFF9F2FBFFF9F0F7FFF9F2FBFFFAF4FEFFFAF4FFFFFAF4 + FFFFFAF4FFFFFAF4FFFFFAF4FEFFF9F2FBFFF9F0F7FFF9F2FBFFFAF4FEFFF9F3 + FEFFF4F0F7FFFFFFFFFFA99585FF00000016000000000000000000000016A896 + 86FFFFFFFFFFC68C38FFCD974BFFD29D52FFD7A051FFA6958BFFFFFFFFFF42B9 + 94FF4BBD9AFF4DBE9BFF4DBD9AFF4DBD9AFF4DBD9AFF4DBE9BFF4DBE9BFF4DBE + 9BFF4DBE9BFF4DBE9BFF4DBE9BFF4DBD9AFF4DBD9AFF4DBD9AFF4DBE9BFF4BBD + 9AFF42B994FFFFFFFFFFAA9585FF00000016000000000000000000000016A896 + 86FFFFFFFFFFC58B37FFCB9649FFD09B4FFFD59E4EFFA6958CFFFFFFFFFF34A4 + 6DFF3DA872FF3FA874FF3FA874FF3FA874FF3FA874FF3FA874FF3FA874FF3FA8 + 74FF3FA874FF3FA874FF3FA874FF3FA874FF3FA874FF3FA874FF3FA874FF3DA8 + 72FF34A46DFFFFFFFFFFAA9585FF00000015000000000000000000000016A896 + 86FFFFFFFFFFC48A35FFCA9447FFCD994DFFD49C4DFFA7978FFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFAB9787FF0000000D000000000000000000000016A896 + 86FFFFFFFFFFC28834FFC89345FFCC974AFFD09B4CFFB89A79FFA7978FFFA695 + 8BFFA7958AFFA7948AFFA6948AFFA6948AFFA69489FFA69389FFA69389FFA693 + 89FFA69389FFA69389FFA69389FFA69389FFA79489FFA79389FFA69286FFA690 + 81FFA89382FFAA9687FF776A60B300000004000000000000000000000016A996 + 86FFFFFFFFFFC08532FFC79143FFCA9549FFCD984CFFD19B4DFFD39E4FFFD7A1 + 52FFD9A357FFDAA75AFFDBA95DFFDEAA60FFDDAC63FFDEAD65FFDEAE66FFDEAE + 67FFDEAE68FFDDAE69FFDCAE69FFDBAD69FFDAAC67FFD7A964FFD3A258FFFFFF + FFFFA99687FF000000160000000000000000000000000000000000000016A996 + 86FFFFFFFFFFBF8330FFC58F41FFC89347FFCA954AFFCD994EFFCF9C51FFD19F + 55FFD4A158FFD6A45CFFD7A660FFD8A861FFD9A963FFD9AA65FFDAAA68FFD9AB + 69FFD9AB6AFFD9AB6BFFD8AB6BFFD7AB6CFFD6AA6BFFD3A766FFCF9E57FFFFFF + FFFFA99686FF000000160000000000000000000000000000000000000016A996 + 86FFFFFFFFFFBD812DFFC38D3FFFC69145FFC89347FFCB964BFFCD994FFFCE9C + 52FFD19F56FFD2A159FFD3A25CFFD5A45EFFD5A661FFD6A763FFD6A864FFD6A8 + 65FFD6A967FFD5A968FFD5A968FFD4A968FFD3A868FFD1A463FFCC9C57FFFFFF + FFFFA89586FF000000160000000000000000000000000000000000000016A996 + 86FFFFFFFFFFBA7F2AFFC18B3DFFC48F42FFC69145FFC89347FFCA964BFFCC99 + 4FFFCE9B52FFD09E55FFD1A058FFD2A15BFFD3A35DFFD3A45FFFD3A561FFD4A5 + 62FFD3A663FFD3A664FFD3A665FFD2A666FFD2A666FFCFA263FFCA9A53FFFFFF + FFFFA89586FF000000160000000000000000000000000000000000000016A996 + 86FFFFFFFFFFBB7F2AFFBE893BFFC28D40FFC48F42FFC69044FFC89348FFCA96 + 4BFFCC984EFFCD9A52FFCE9C55FFCF9E57FFD0A059FFD1A15CFFD1A25DFFD1A2 + 5FFFD1A360FFD1A361FFD1A362FFD0A362FFCFA363FFCDA05FFFC99952FFFFFF + FFFFA89586FF000000160000000000000000000000000000000000000016A996 + 86FFFFFFFFFFBA7E28FFBE8637FFBE8839FFC18A3CFFC38C3EFFC48E41FFC691 + 45FFC89348FFC9954BFFCB974EFFCC9950FFCD9B53FFCD9C55FFCD9D57FFCE9D + 58FFCE9E59FFCE9E5AFFCD9F5BFFCD9E5CFFCC9E5DFFCB9D5BFFC6954EFFFFFF + FFFFA89586FF000000160000000000000000000000000000000000000015A996 + 86FFFFFFFFFFB7781DFFBA7E28FFBB7F2AFFBA7F2AFFBB802CFFBE822EFFC085 + 32FFC18835FFC38A38FFC48C3CFFC58F3FFFC69041FFC89143FFC89246FFC793 + 47FFC79449FFC7944AFFC8954BFFC8954CFFC6954DFFC6944CFFC48F44FFFFFF + FFFFA89586FF00000015000000000000000000000000000000000000000DAA97 + 87FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFAA9787FF0000000D0000000000000000000000000000000000000004786B + 61B4AA9787FFA99686FFA99686FFA99686FFA99686FFA99686FFA99686FFA996 + 86FFA99686FFA89686FFA89686FFA89686FFA89586FFA89586FFA89586FFA895 + 86FFA89586FFA89586FFA89586FFA89586FFA89586FFA89586FFA99586FFAA97 + 87FF786B61B40000000400000000000000000000000000000000} + end + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000005000000100000001600000016000000160000 + 0016000000160000001600000016000000160000001600000016000000160000 + 0016000000160000001600000016000000150000000D00000004000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000010000000310000004200000043000000430000 + 0043000000430000004300000043000000430000004300000043000000430000 + 00430000004300000043000000430000003F0000002B0000000D000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000016A5A5A4F1AFAFADFFAEAEABFFADADABFFADAD + ABFFADADABFFADADABFFADADABFFADADABFFADADABFFADADABFFADADABFFADAD + ABFFADADABFFADADABFFAEAEABFFAFAFADFF7C7C7AC400000015000000040000 + 000D000000150000001600000016000000160000001600000016000000160000 + 0016000000160000001600000027B0B0ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0B0ADFF000000160000000D0000 + 002B0000003F0000004300000043000000430000004300000043000000430000 + 0043000000430000004300000048B1B0ACFFFFFFFFFFFFFFFFFFFEFEFFFFFEFE + FFFFFEFEFFFFFEFEFFFFFEFEFFFFFEFEFFFFFEFEFFFFFEFEFFFFFEFEFFFFFEFE + FFFFFEFEFFFFFEFEFFFFFFFFFFFFFFFFFFFFAEAEABFF00000016000000152C48 + 66C43F6893FF3F6893FF3F6893FF3F6893FF3F6893FF3F6893FF3F6893FF3F68 + 93FF3E6793FF376391FF376391FFB5B2ADFFFFFFFFFFFCFCFCFFFCFCFCFFFCFC + FCFFFCFCFCFFFCFCFCFFFBFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFBFC + FCFFFCFCFCFFFCFCFCFFFCFCFCFFFFFFFFFFADADABFF00000016000000164068 + 93FF5085ACFF4C80AAFF4C80AAFF4C80AAFF4C80AAFF4C80AAFF4C80AAFF4C80 + AAFF4C80AAFF487DA9FF487DA9FFB6B2ADFFFFFFFFFFFDFCFCFFFFFEFEFFFFFE + FEFFFFFEFEFFFEFDFDFFFEFCFCFFFFFEFEFFFFFEFEFFFFFEFEFFFEFDFDFFFEFC + FCFFFFFEFEFFFEFDFDFFFCFBFBFFFFFFFFFFADADABFF00000016000000163F68 + 94FF588AB1FF4C80AAFF4C80AAFF4C80AAFF4C80AAFF4C80AAFF4C80AAFF4C80 + AAFF4C80AAFF487EAAFF487EAAFFB6B2ACFFFFFFFFFFFDFDFDFF818181FFB6B6 + B6FFB5B5B5FFB3B3B3FFFFFFFFFF818181FFB6B6B6FFB5B5B5FFB3B3B3FFFFFF + FFFF808080FFB3B3B3FFFBFCFCFFFFFFFFFFADADABFF00000016000000164069 + 94FF5F8FB5FF4C82ACFF4D82ACFF4D82ACFF4D82ACFF4D82ACFF4D82ACFF4D82 + ACFF4D82ACFF4980ACFF4980ACFFB6B2ACFFFFFFFFFFFCFBFBFFFFFFFFFFFFFF + FFFFFFFEFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE + FEFFFFFFFFFFFFFEFEFFFAF9F9FFFFFFFFFFADADABFF00000016000000163F6A + 94FF6595BAFF4E82AEFF4F83AEFF4F83AEFF4F83AEFF4F83AEFF4F83AEFF4F83 + AEFF4F83AEFF4B81AEFF4B81AEFFB6B2ACFFFFFFFFFFFAFAF9FF818181FFB5B5 + B4FFFDFEFCFF828383FFB6B6B5FFB4B4B3FFFDFEFCFF838383FFB6B6B5FFB5B6 + B4FFB5B5B4FFB2B2B1FFF8F8F7FFFFFFFFFFADADABFF00000016000000163F6A + 95FF6C9ABFFF4E84B0FF5085B0FF5085B0FF5085B0FF5085B0FF5085B0FF5085 + B0FF5085B0FF4C83B0FF4C83B0FFB6B1ABFFFFFFFFFFF8F7F7FFFDFCFCFFFEFC + FCFFFCFBFBFFFDFCFCFFFCFBFCFFFDFCFCFFFDFBFCFFFEFCFDFFFDFCFCFFFCFB + FBFFFDFCFCFFFBFAFAFFF7F6F6FFFFFFFFFFADADABFF00000016000000163F6A + 95FF739FC3FF4F86B1FF5187B2FF5187B2FF5187B2FF5187B2FF5187B2FF5187 + B2FF5187B2FF4D85B2FF4D85B2FFB6B1ABFFFFFFFFFFF6F7F5FF838384FFB6B6 + B5FFB4B4B3FFB3B3B2FFFAFAF9FF838484FFB5B5B4FFB5B5B4FFB3B3B2FFFAFA + F9FF828282FFB3B3B2FFF5F5F4FFFFFFFFFFADADABFF00000016000000163E6A + 96FF7AA5C8FF4F86B3FF5188B4FF5288B4FF5288B4FF5288B4FF5288B4FF5288 + B4FF5288B4FF4E86B4FF4E86B4FFB6B1ABFFFFFFFFFFF5F4F2FFFAF9F8FFFAF9 + F8FFF9F8F7FFF9F8F7FFF9F8F7FFFAF9F7FFF9F8F7FFFAF9F8FFFAF9F7FFF9F8 + F7FFFAF9F8FFF8F7F5FFF3F2F1FFFFFFFFFFADADABFF00000016000000163F6B + 95FF81AACCFF5188B5FF548AB6FF548AB6FF548AB6FF548AB6FF548AB6FF548A + B6FF548AB6FF5088B6FF5088B6FFB5B1ABFFFFFFFFFFF3F2F2FF828283FFB3B3 + B3FFF7F6F6FF848484FFB3B3B3FFB1B2B2FFF7F6F6FF848585FFB4B4B4FFB3B3 + B3FFB3B3B3FFB0B0B0FFF1F0F0FFFFFFFFFFADADABFF00000016000000163F6C + 96FF87B0CFFF528AB7FF548CB8FF558CB8FF558CB8FF558CB8FF558CB8FF558C + B8FF558CB8FF518AB8FF518AB8FFB5B1ABFFFFFFFFFFF1F0EFFFF7F6F4FFF7F6 + F5FFF6F5F3FFF6F5F4FFF6F5F4FFF6F5F4FFF6F5F4FFF7F6F5FFF7F5F4FFF6F5 + F4FFF7F6F5FFF5F3F2FFF0EFEEFFFFFFFFFFADADABFF00000016000000163E6C + 97FF8EB4D4FF528BB9FF558DBAFF568DBAFF568DBAFF568DBAFF568DBAFF568D + BAFF568DBAFF528BBAFF528BBAFFB5B1ABFFFFFFFFFFEFEEEEFF858585FFB3B3 + B3FFB2B2B2FFB0B0B1FFF4F2F3FF858585FFB3B3B3FFB2B2B2FFB0B1B1FFF4F3 + F3FF848484FFB0B0B1FFEEEDEDFFFFFFFFFFADADABFF00000016000000163F6C + 98FF94BAD8FF538DBBFF568FBCFF578FBCFF578FBCFF578FBCFF578FBCFF578F + BCFF578FBCFF538DBCFF538DBCFFB5B1ABFFFFFFFFFFEDEDECFFF2F2F1FFF3F3 + F2FFF2F2F1FFF0F0EFFFF2F2F0FFF3F3F2FFF3F3F2FFF2F2F1FFF0F0EFFFF2F2 + F1FFF3F3F2FFF0F0EFFFECECEAFFFFFFFFFFADADABFF00000016000000163E6D + 98FF9ABDDBFF538DBEFF578FBFFF5890BFFF5890BFFF5890BFFF5890BFFF5890 + BFFF5890BFFF548EC0FF548EC0FFB5B1AAFFFFFFFFFFECEBEAFF858586FFB2B2 + B1FFB0B0AFFFF0EFEEFF868686FFB2B3B1FFB1B1B0FFB0B0AFFFF0EFEEFF8485 + 85FFB2B2B1FFAFAFAEFFEBEAE8FFFFFFFFFFADADABFF00000016000000163F6E + 98FFA1C3DEFF558FC0FF5991C1FF5A92C1FF5A92C1FF5A92C1FF5A92C1FF5A92 + C1FF5A92C1FF5790C2FF5790C2FFB5B0AAFFFFFFFFFFE9E9E8FFEFEFEEFFEFEF + EEFFEDEDECFFEEEEEDFFF0F0EFFFEFEFEEFFEEEEEDFFEFEFEEFFEEEFEDFFEFF0 + EEFFEFEFEEFFECEDECFFE8E8E7FFFFFFFFFFAEAEABFF00000016000000163E6E + 99FFA7C8E1FF5691C1FF5A93C3FF5B94C3FF5B94C3FF5B94C3FF5B94C3FF5B94 + C3FF5B94C3FF5893C4FF5893C4FFB5B0AAFFFFFFFFFFE8E7E6FF848484FFB0AF + AFFFECEBEAFF868686FFB1B0B0FFAFAEAEFFECEBEAFF868686FFB1B0B0FFB1B0 + B0FFB0AFAFFFAEADADFFE7E6E4FFFFFFFFFFAEAEABFF00000016000000163E6F + 99FFADCDE5FF5792C3FF5B94C5FF5C95C5FF5C95C5FF5C95C5FF5C95C5FF5C95 + C5FF5C95C5FF5994C6FF5994C6FFB5B0AAFFFFFFFFFFE4E3E3FFE7E6E6FFE7E6 + E6FFE6E5E6FFE8E7E7FFE8E7E7FFE7E6E6FFE6E5E5FFE8E7E7FFE8E7E7FFE7E6 + E6FFE7E6E6FFE6E5E5FFE3E2E2FFFFFFFFFFAEAEABFF00000016000000163F6E + 9AFFB3D0E8FF5794C5FF5C96C7FF5D97C7FF5D97C7FF5D97C7FF5D97C7FF5D97 + C7FF5D97C7FF5A96C8FF5A96C8FFB5B0AAFFFFFFFFFFE0DFDEFFE1E0DFFFE2E1 + DFFFE2E0DFFFE2E1DFFFE2E1DFFFE2E0DFFFE1E0DFFFE2E1DFFFE2E1DFFFE2E1 + DFFFE2E1DFFFE1E0DFFFE0DFDEFFFFFFFFFFAEAEACFF00000015000000163E6F + 9BFFB9D4EBFF5896C7FF5D98C9FF5E99C9FF5E99C9FF5E99C9FF5E99C9FF5E99 + C9FF5E99C9FF5B98CAFF5B98CAFFBAB3ABFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFAFADFF0000000D000000163E70 + 9AFFBFD9EEFF5A96C9FF5F99CBFF609ACBFF609ACBFF609ACBFF609ACBFF609A + CBFF609ACBFF5F99CBFF5A98CDFF98AAB8FFBAB3AAFFB7B0A9FFB7B0A9FFB7B0 + A9FFB7B0A9FFB6B0A9FFB5AFA8FFB3AFA9FFB3B0ABFFB1AFACFFAFAEACFFAEAE + ABFFAEAEABFFAEAEABFFAEAEACFFB0B0ADFF7C7C7AB400000004000000163E71 + 9BFFC4DCF0FF5A98CBFF609BCDFF619CCDFF619CCDFF619CCDFF609CCEFF609C + CEFF609CCEFF609CCEFF5E9BCFFF5B9ACFFF5799CFFF5698CFFF5698CFFF5798 + CFFF5798CEFF5697CEFF5295CDFFBCD9F1FF2F6899FF00000016000000000000 + 0000000000000000000000000000000000000000000000000000000000163E72 + 9CFFCBE1F3FF5B9ACDFF609DCFFF629ECFFF619ED0FF5E9ED2FF5C9ED3FF5B9E + D4FF5B9ED4FF5B9ED4FF5B9ED4FF5A9DD4FF5A9DD4FF5B9DD4FF5D9ED2FF5F9E + D1FF609ED0FF5F9DCFFF5A9ACEFFC9E0F4FF396F9BFF00000016000000000000 + 0000000000000000000000000000000000000000000000000000000000163F71 + 9DFFD0E6F5FF5B9ACFFF619DD0FF629ED1FF5F9FD4FF8699A8FF9C948DFF9993 + 8EFF99938EFF99938EFF99938EFF99938EFF99938EFF9C948DFF8699A8FF5F9F + D4FF629ED1FF619DD0FF5B9ACFFFD0E6F5FF3E719DFF00000016000000000000 + 0000000000000000000000000000000000000000000000000000000000153F73 + 9DFFD8E8F8FF5A9CD1FF5E9ED2FF5F9FD3FF5B9FD7FF9A938DFFFAF7F5FFE7E4 + E3FFE7E4E3FFE7E4E3FFE7E4E3FFE7E4E3FFE7E4E3FFFAF7F5FF9B938DFF5B9F + D7FF5F9FD3FF5E9ED2FF5A9CD1FFD8E8F8FF3F739DFF00000015000000000000 + 00000000000000000000000000000000000000000000000000000000000D4276 + A0FFAFD2F1FFADD0EEFFAED0EDFFAED1EEFFAAD1F2FF97928EFFE6E4E2FFC8C4 + C3FFC7C4C3FFC7C4C3FFC7C4C3FFC7C4C3FFC8C4C3FFE6E4E2FF98928EFFAAD1 + F2FFAED1EEFFAED0EDFFADD0EEFFAFD2F1FF4276A0FF0000000D000000000000 + 0000000000000000000000000000000000000000000000000000000000043155 + 71B44478A1FF4276A0FF4276A0FF4176A0FF3B74A2FF9B9692FFD7D3D2FFD2D0 + CFFFCFCDCCFFCECCCAFFCDCBCAFFCDCBCAFFCFCDCCFFD2CFCDFF9B9692FF3B74 + A2FF4176A0FF4276A0FF4276A0FF4478A1FF315571B400000004000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000D9090 + 90FFE5E5E5FFE3E3E3FFE3E3E3FFE5E5E5FF909091FF0000000D000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000046767 + 67B3959595FF949494FF949494FF959595FF676767B300000004000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000} + end + item + Image.Data = { + 36100000424D3610000000000000360000002800000020000000200000000100 + 2000000000000010000000000000000000000000000000000000000000000000 + 0000000000040000000D00000015000000160000001600000016000000160000 + 00160000001600000016000000150000000D0000000400000000000000000000 + 00040000000D0000001500000016000000160000001600000016000000160000 + 001600000016000000150000000D000000040000000000000000000000000000 + 00000000000D0000002B0000003F000000430000004300000043000000430000 + 004300000043000000430000003F0000002B0000000D00000000000000000000 + 000D0000002B0000003F00000043000000430000004300000043000000430000 + 0043000000430000003F0000002B0000000D0000000000000000000000000000 + 000000000015555553C4797675FF747371FF716F6DFF6F6C6BFF6C6968FF6A68 + 66FF696665FF676463FF646160FF444141C40000001500000000000000000000 + 0015555553C4797675FF747371FF716F6DFF6F6C6BFF6C6968FF6A6866FF6966 + 65FF676463FF646160FF444141C4000000150000000000000000000000000000 + 0000000000167B7977FF7F7B7AFF928F8EFFA29F9DFF989593FF8B8987FF7F7C + 7BFF72706FFF656461FF595655FF625F5EFF0000001600000000000000000000 + 00167B7977FF7F7B7AFF928F8EFFA29F9DFF989593FF8B8987FF7F7C7BFF7270 + 6FFF656461FF595655FF625F5EFF000000160000000000000000000000000000 + 000000000016797775FF7A7776FF8B8887FF9A9795FF908D8BFF83817FFF7875 + 74FF6C6A69FF615F5CFF565251FF605D5CFF0000001600000000000000000000 + 0016797775FF7A7776FF8B8887FF9A9795FF908D8BFF83817FFF787574FF6C6A + 69FF615F5CFF565251FF605D5CFF000000160000000000000000000000000000 + 000000000016777573FFDBDAD8FFE2E2E1FFEBECEBFFE3E3E2FFDAD9D8FFD0CF + CFFFC8C7C6FFBEBEBCFFB7B5B5FF5F5C5BFF0000001600000000000000000000 + 0016777573FFDBDAD8FFE2E2E1FFEBECEBFFE3E3E2FFDAD9D8FFD0CFCFFFC8C7 + C6FFBEBEBCFFB7B5B5FF5F5C5BFF000000160000000000000000000000000000 + 000000000016787674FF7D7B7AFF898786FF949291FF8A8988FF7D7C7BFF7370 + 6FFF676665FF5B5A59FF4F4E4DFF605D5CFF0000001600000000000000000000 + 0016787674FF7D7B7AFF898786FF949291FF8A8988FF7D7C7BFF73706FFF6766 + 65FF5B5A59FF4F4E4DFF605D5CFF000000160000000000000000000000000000 + 000000000016787674FFB1AFADFFC1C0BEFFD0CFCDFFC3C2C0FFB3B2B0FFA3A1 + A0FF939190FF848281FF747271FF605D5CFF0000002700000016000000160000 + 0027797775FFB1AFADFFC1C0BEFFD0CFCDFFC3C2C0FFB3B2B0FFA3A1A0FF9391 + 90FF848281FF747271FF605D5CFF000000160000000000000000000000000000 + 000000000016777573FFB0AEACFF888685FFCFCECCFF888787FFB2B1AFFF7371 + 70FF939190FF5C5B5AFF737170FF5E5B5AFF0000004800000043000000430000 + 0048797775FFB0AEACFF888685FFCFCECCFF888787FFB2B1AFFF737170FF9391 + 90FF5C5B5AFF737170FF605D5CFF000000160000000000000000000000000000 + 000000000016777573FFAFADABFFBEBDBBFFCDCCCAFFC0BFBDFFB0AFADFFA19F + 9EFF92908FFF82807FFF72706FFF5C5958FF797675FF6D6B69FF666262FF5D5A + 59FF787674FFAFADABFFBEBDBBFFCDCCCAFFC0BFBDFFB0AFADFFA19F9EFF9290 + 8FFF82807FFF72706FFF605D5CFF000000160000000000000000000000000000 + 000000000016777573FFAEACAAFFBDBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D + 9CFF908E8DFF817F7EFF716F6EFF595655FFBEBCBAFFCDCBCAFFA3A1A0FF7A78 + 77FF767472FFAEACAAFFBDBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D9CFF908E + 8DFF817F7EFF72706FFF605D5CFF000000160000000000000000000000000000 + 000000000016777573FFAEACAAFFBCBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D + 9CFF908E8DFF817F7EFF716F6EFF585554FFE3E3E1FFE9EAE9FFD1D0CFFFB8B8 + B7FF757371FFAEACAAFFBCBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D9CFF908E + 8DFF817F7EFF72706FFF605D5CFF000000160000000000000000000000000000 + 000000000016777573FFAEACAAFFBCBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D + 9CFF908E8DFF817F7EFF716F6EFF5B5857FF787574FF6B6966FF63605FFF5B58 + 57FF777573FFAEACAAFFBCBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D9CFF908E + 8DFF817F7EFF72706FFF605D5CFF000000160000000000000000000000000000 + 000000000016767472FFADABA9FFBBBBB9FFCBCAC8FFBEBDBBFFAEADABFF9F9D + 9CFF908E8DFF817F7EFF72706FFF5E5B5AFF0000001600000000000000000000 + 0016787674FFAEACAAFFBCBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D9CFF908E + 8DFF807E7DFF706E6DFF5F5C5BFF000000160000000000000000000000000000 + 000000000015767371FFCCCDCCFFBAB9B7FFCAC9C7FFBEBDBBFFAEADABFF9F9D + 9CFF908E8DFF817F7EFF72706FFF5F5C5BFF0000001600000000000000000000 + 0016777573FFAEACAAFFBCBCBAFFCBCAC8FFBEBDBBFFAEADABFF9F9D9CFF8F8D + 8CFF7E7C7BFF979696FF5E5B5AFF000000150000000000000000000000000000 + 00000000000D767472FFCAC9C9FFCECECDFFCAC9C7FFBDBCBAFFAEADABFF9E9C + 9BFF8F8D8CFF807E7DFF716F6EFF605D5CFF0000001600000000000000000000 + 0016777573FFAEACAAFFBCBBB9FFCBCAC8FFBDBCBAFFAEADABFF9E9C9BFF8D8B + 8AFF9F9E9DFF959393FF5E5B5AFF0000000D0000000000000000000000000000 + 000000000004514F4EB3918E8CFFD0CFCFFFD3D4D3FFBEBDBBFFADACA9FF9D9B + 9AFF8D8B8AFF7E7C7BFF6F6D6CFF5F5C5BFF0000001400000000000000000000 + 0014767472FFADABA9FFBBBAB8FFCAC9C7FFBDBCBAFFADACA9FF9D9B9AFFA9A8 + A8FF9F9E9DFF676564FF413E3EB3000000040000000000000000000000000000 + 000000000000000000034C4B4AAE7F7D7AFFC7C6C5FFD2D1D2FFD9D8D7FFCDCD + CDFFC5C4C3FFBBBBBAFFB5B3B3FF5E5B5AFF0000001200000000000000000000 + 0012777573FFD9D8D6FFE1E0DFFFEAEAE9FFE2E2E1FFD9D9D8FFB7B6B5FFA4A1 + A2FF676564FF403E3DAE00000003000000000000000000000000000000000000 + 00000000000000000000000000034A4847AE6B6967FF646160FF5E5B5AFF5C5A + 58FF5C5958FF5C5958FF5D5A59FF3B3838B60000002500000016000000160000 + 00254A4947B66F6C6BFF676563FF63615FFF635F5FFF63605FFF64625FFF6562 + 61FF413F3EAE0000000300000000000000000000000000000000000000000000 + 000000000000000000000000000000000016787674FFB5B3B1FFD0CFCDFFC2C1 + BFFFA9A7A6FF908E8DFF767473FF5F5C5BFF0000004800000043000000430000 + 0048797775FFB5B3B1FFCFCECCFFC1C0BEFFA8A6A5FF8F8D8CFF757373FF605D + 5CFF000000160000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000016777573FFB2B0AEFFCBCAC8FFBDBC + BAFFA5A3A2FF8E8C8BFF757372FF5D5A59FF797675FF6D6B69FF666262FF5D5A + 59FF787674FFB2B0AEFFCBCAC8FFBDBCBAFFA5A3A2FF8D8B8AFF767473FF615D + 5CFF000000160000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000016767472FFB1AFADFFCAC9C7FFBCBB + B9FFA4A2A1FF8D8B8AFF747271FF595655FFBEBCBAFFCDCBCAFFA3A1A0FF7A78 + 77FF767472FFB1AFADFFCAC9C7FFBCBBB9FFA4A2A1FF8D8B8AFF757372FF615D + 5CFF000000160000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000016767472FFB1AFADFFCAC9C7FFBCBB + B9FFA4A2A1FF8C8A89FF737170FF585554FFE3E3E0FFE9EAE9FFD1D0CFFFB8B8 + B7FF747270FFB1AFACFFCAC9C7FFBCBBB9FFA4A2A1FF8C8A89FF757371FF605D + 5CFF000000160000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000014767472FFB0AEACFFC9C8C6FFBAB9 + B7FFA2A09FFF8A8887FF72706FFF5B5857FF787574FF6B6966FF63605FFF5B58 + 57FF767472FFB0AEACFFC9C8C6FFBAB9B7FFA2A09FFF8A8887FF737170FF605C + 5BFF000000140000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000D777573FFDCDBD9FFE9EAE8FFE1E0 + E0FFD2D0D1FFC4C3C2FFB6B5B6FF5D5A59FF0000000D00000000000000000000 + 000D787674FFDCDBD9FFE9EAE8FFE1E0E0FFD2D0D1FFC4C3C2FFB6B6B6FF5F5C + 5AFF0000000D0000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000044F4E4DB2716D6DFF676563FF615F + 5DFF605D5CFF615D5CFF605E5CFF3F3D3CB10000000300000000000000000000 + 00034F4E4DB1716E6DFF676563FF615F5DFF605D5CFF615D5CFF605F5CFF403E + 3DB2000000040000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000040000001E777473FFBCBAB8FFCECC + CBFFA5A3A2FF7E7C7BFF605C5CFF0000001E0000000400000000000000000000 + 00040000001E777473FFBCBAB8FFCECCCBFFA5A3A2FF7E7C7BFF605C5CFF0000 + 001E000000040000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000D00000030787574FFBEBCBAFFCFCD + CCFFA6A4A3FF807E7DFF605D5CFF000000300000000D00000000000000000000 + 000D00000030787574FFBEBCBAFFCFCDCCFFA6A4A3FF807E7DFF605D5CFF0000 + 00300000000D0000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000014514F4EBD757271FF6C6A68FF6765 + 63FF666362FF666362FF656361FF413F3FBD0000001400000000000000000000 + 0014514F4EBD757271FF6C6A68FF676563FF666362FF666362FF656361FF413F + 3FBD000000140000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000167A7876FF807D7CFF9B9896FF9490 + 8EFF7E7C7AFF6C6A67FF595756FF615E5DFF0000001600000000000000000000 + 00167A7876FF807D7CFF9B9896FF94908EFF7E7C7AFF6C6A67FF595756FF615E + 5DFF000000160000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000011797775FFBEBCBBFFCDCCCBFFC7C7 + C6FFBDBABAFFB1AFAFFFA7A5A6FF605D5CFF0000001100000000000000000000 + 0011797775FFBEBCBBFFCDCCCBFFC7C7C6FFBDBABAFFB1AFAFFFA7A5A6FF605D + 5CFF000000110000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000067B7977FF757271FF6F6D6BFF6A68 + 66FF686564FF656261FF63615EFF615E5DFF0000000600000000000000000000 + 00067B7977FF757271FF6F6D6BFF6A6866FF686564FF656261FF63615EFF615E + 5DFF000000060000000000000000000000000000000000000000} + end> + end + object DockingManager: TdxDockingManager + Color = clBtnFace + DefaultHorizContainerSiteProperties.CustomCaptionButtons.Buttons = <> + DefaultHorizContainerSiteProperties.Dockable = True + DefaultHorizContainerSiteProperties.ImageIndex = -1 + DefaultVertContainerSiteProperties.CustomCaptionButtons.Buttons = <> + DefaultVertContainerSiteProperties.Dockable = True + DefaultVertContainerSiteProperties.ImageIndex = -1 + DefaultTabContainerSiteProperties.CustomCaptionButtons.Buttons = <> + DefaultTabContainerSiteProperties.Dockable = True + DefaultTabContainerSiteProperties.ImageIndex = -1 + DefaultTabContainerSiteProperties.TabsProperties.CustomButtons.Buttons = <> + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Images = imgMisc + LookAndFeel.NativeStyle = False + Left = 624 + Top = 176 + PixelsPerInch = 96 + end + object imgMisc: TcxImageList + FormatVersion = 1 + DesignInfo = 15729048 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000240000 + 0033000000330000003300000033000000330000003300000033000000330000 + 00330000003300000033000000330000003300000033000000247E5606C1B67E + 0EFFB57C09FFB57C09FFB57C09FFB57B08FFB47B08FFB57B08FFB57B08FFB47B + 08FFB57B08FFB57B08FFB57B08FFB57C09FFB67E0EFF7E5606C1B67E0EFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB67E0EFFB57C09FFFFFF + FFFFA09D9EFF8F8F8FFF939291FFD2D1D2FFFFFFFFFFC1C2C3FFC1C2C4FFFFFF + FFFFC1C2C4FFC3C4C6FFC3C4C6FFC2C4C7FFFFFFFFFFB57B09FFB57B08FFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB47B08FFB57B08FFFFFF + FFFF999696FF8B8886FF8F8C8AFFCAC9C8FFFCFCFBFFBBBBBBFFBBBBBBFFFCFC + FBFFBBBBBBFFBDBDBDFFBDBDBDFFBBBCBEFFFFFFFFFFB57B08FFB57B08FFFFFF + FFFFFCFDFEFFFFFFFFFFFFFFFEFFFAFAF9FFF7F7F6FFF8F8F7FFF8F8F7FFF7F7 + F6FFF8F9F7FFFAFAF9FFFAFAF9FFF8F9F9FFFFFFFFFFB57B08FFB57B08FFFFFF + FFFF92908FFF868381FF888684FFC4C1BFFFF3F2F1FFB3B2B2FFB3B2B2FFF4F2 + F1FFB3B2B2FFB5B4B4FFB5B4B4FFB2B2B4FFFFFFFFFFB57B08FFB57B08FFFFFF + FFFFF2F1F2FFF6F5F5FFF5F4F4FFF0F0EFFFEEEDECFFEFEEEDFFEFEEEDFFEEED + ECFFEFEEEDFFF1F0EFFFF1F0EFFFEEEEEEFFFFFFFFFFB57B08FFB57C09FFFFFF + FFFF8B8988FF807E7CFF83817FFFBABAB7FFE9E8E7FFACABAAFFADACABFFE9E8 + E7FFADACABFFAFAEADFFAEADACFFABABABFFFFFFFFFFB57B08FFB57B09FFFFFF + FFFFE6E6E5FFEBEAE8FFEAE9E7FFE5E4E2FFE2E1DFFFE4E3E1FFE4E3E1FFE3E2 + DFFFE4E3E1FFE6E5E2FFE5E4E2FFE2E2E1FFFFFFFFFFB57B08FFB57C09FFFFFF + FFFF807E7DFF767372FF797776FFAEADACFFDADAD9FFA1A09FFFA1A09FFFDADA + DAFFA1A1A0FFA2A2A1FFA2A2A1FF9F9FA0FFFFFFFFFFB57B09FFB57C0BFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB57C0BFFB67F10FFF5DD + B7FFDC9D37FFDC9E39FFDC9F3AFFDB9E39FFDB9E39FFDB9E39FFDB9E39FFDB9E + 39FFDB9E39FFDC9E39FFDB9E39FFDB9D37FFF5DDB7FFB67F10FFB88216FFEFD0 + 9EFFECCD99FFECCD99FFECCD9AFFECCD9AFFECCD9AFFECCD9AFFECCD9AFFECCD + 9AFFECCD9AFFECCD9AFFECCD99FFECCD99FFEFD09EFFB88216FF7E5606B2B882 + 17FFB78115FFB68114FFB68115FFB68115FFB68115FFB68115FFB68115FFB681 + 15FFB68115FFB68115FFB68114FFB78115FFB88217FF7E5606B2} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0023000000330000003300000033000000330000003300000033000000330000 + 003300000033000000330000002600000003000000000000000000000000695B + 4BC096816AFF958069FF958069FF95816AFF95846FFF988169FFA76730FFAF59 + 10FFAD5911FFAE5A13FF824411CA0905013D0000000300000000000000009884 + 6CFFD4CAB7FFCFC4AFFFCFC4AFFFCFC7B3FFCCBDA5FFB05B12FFCD8B47FFE6B5 + 75FFE4B271FFE6B676FFCD8E4CFFAE5B15FF0905013100000000000000009883 + 6DFFD7CCBAFFDDC9B6FFCCC2ADFFDECFC0FFB7773CFFCA833EFFDEAA66FFDAA2 + 5BFFFFFFFFFFDAA25BFFDEAA68FFCB8846FF834511CA00000000000000009A85 + 6DFFDAD0C0FFCEC1ADFFCEC3AFFFD0C9BAFFAB4F02FFDAA05CFFD69C58FFD394 + 4CFFFFFFFFFFD3944CFFD69C58FFDBA360FFAF5B15FF00000000000000009A85 + 6FFFDFD7C6FFD1C5B1FFD2C6B3FFD3CDBFFFAB5003FFDDAB73FFD19149FFCF8C + 41FFFFFFFFFFCF8C41FFD19149FFDEAD76FFAE5A13FF00000000000000009C87 + 71FFE4DBCEFFB9A189FFBAA38CFFBCA996FFAA4E00FFEACBA7FFCB8639FFCA84 + 36FFC88130FFCA8436FFCB873AFFEACEABFFAE5A12FF00000000000000009D88 + 71FFE6DFD3FFF0DFCFFFF0E0D2FFF1E5DAFFC27F46FFD09A67FFE0B78AFFC882 + 36FFFFFFFFFFC88336FFE1B98CFFD2A070FF82450FBE00000000000000009F8A + 73FFEBE5D9FFB79F86FFB7A189FFB9A48DFFBA9F84FFAB5308FFCD9661FFE9CC + ACFFE9CBAAFFEACEB0FFCF9C6BFFAE5911FF0905010D0000000000000000A08A + 75FFEEE8DFFFEEDDCEFFEFDFD0FFF0E0D2FFF0E3D6FFEAD5C3FFC07F47FFAC50 + 02FFAD550AFFAD580FFF82430EBD0905010D000000000000000000000000A28C + 75FFF2ECE4FFB69E85FFB7A087FFB7A088FFB7A189FFB7A18AFFF3F2EDFFA094 + 83FF00000000000000000000000000000000000000000000000000000000A28D + 77FFF5F0E8FFECDACAFFECDBCCFFEDDCCCFFECDBCCFFECDBCBFFF5F1EAFFA290 + 7CFF00000000000000000000000000000000000000000000000000000000A58F + 79FFF8F3ECFFDACAB6FFD9CAB6FFDACAB7FFD9CAB6FFDACAB6FFF8F3ECFFA48F + 7AFF00000000000000000000000000000000000000000000000000000000A691 + 7BFFFCF9F3FFF8F3EFFFF8F2EEFFF8F2EEFFF8F2EEFFF8F3EFFFFCF9F3FFA691 + 7BFF000000000000000000000000000000000000000000000000000000007366 + 56ACC5B5A0FFD9CBB7FFD8CAB6FFD8CAB5FFD8CAB6FFD9CBB7FFC5B5A0FF7366 + 56AC000000000000000000000000000000000000000000000000000000000000 + 0000746758ACAC9782FFAB9781FFAB9781FFAB9781FFAC9782FF746758AC0000 + 0000000000000000000000000000000000000000000000000000} + end> + end + object popupEditor: TdxRibbonPopupMenu + BarManager = BarManager + ItemLinks = < + item + Visible = True + ItemName = 'dxBarSeparator1' + end + item + Visible = True + ItemName = 'lbCreateDefinition' + end + item + Visible = True + ItemName = 'dxBarSeparator2' + end + item + Visible = True + ItemName = 'bbDuplicateDefinition' + end + item + Visible = True + ItemName = 'bbDeleteDefinition' + end + item + Visible = True + ItemName = 'dxBarSeparator4' + end + item + Visible = True + ItemName = 'bbExpandLeaf' + end + item + Visible = True + ItemName = 'bbCollapseLeaf' + end + item + Visible = True + ItemName = 'dxBarSeparator3' + end + item + Visible = True + ItemName = 'lbClipboardPaste' + end + item + Visible = True + ItemName = 'bbClipboardCopy' + end + item + Visible = True + ItemName = 'bbClipboardCut' + end> + Ribbon = Ribbon + UseOwnFont = False + Left = 480 + Top = 240 + end + object imgTreeView: TcxImageList + FormatVersion = 1 + DesignInfo = 15729264 + ImageInfo = < + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000220000 + 0033000000330000003300000033000000330000002200000000000000000000 + 000000000000000000000000000000000000000000000000002A77736BBCB0AA + 9EFFAFA99DFFAEA89CFFAEA99CFFB0AA9EFF77736BBC0000002B000000000000 + 000B0000000A0000000A0000000A0000000A000000079B8F81DBBAB3A6FFD3CA + C1FFE4DAD2FFEFE4DDFFE8DDD6FFD5CDC4FFB9B4A7FF959085DD0000002F0F21 + 2D5F0E1F2A5C0E1F2A5C0E1F2A5C0D1D285908161F51BCAD9AFFCBC3B8FFD4CC + C4FFE1D6CEFFEBE1D9FFE4DAD2FFD7D0C7FFCDC6BCFFB1AB9FFF4190C5F14398 + D2FF4094D0FF3E92CFFF3E92CEFF3D92D0FF3592D5FFBAAA98FFCAC2B7FFD3CB + C2FFDFD5CDFFEAE0D8FFE3D8D0FFD6CEC5FFCCC5BBFFB0AA9EFF4499D2FF3F94 + D0FFABFBFFFF9BF3FFFF92F1FFFF92F1FFFF8CF4FFFFB6A695FFC8BFB4FFD1C8 + C0FFDED3CBFFE8DED6FFE1D6CEFFD4CCC3FFCAC3B9FFB0AA9EFF4397D1FF56AC + DDFF8EDAF5FFA2EDFFFF82E5FEFF83E6FFFF7EEAFFFFB4A493FFE5DDD5FFF8F4 + EEFFFDF9F2FFF9F5EDFFFDF8F2FFF9F4EEFFE6DFD8FFAEA99CFF4296D1FF71C4 + EAFF6CBCE6FFBBF2FFFF75DEFDFF75DFFEFF73E3FFFFB4A392FFF0E5DCFFDDD3 + C8FFD8CFC5FFD8CFC5FFD8CFC5FFDDD3C8FFEFE7DEFFB0A99CFF4095D0FF90DD + F8FF44A0D8FFDDFCFFFFDAFAFFFFDAFAFFFFD9FDFFFFA5B3AEFFD1C2B4FFEBE0 + D5FFEDE4DAFFEDE4DAFFEDE4DAFFEAE0D5FFD0C4B6FF928779D13E93CFFFB2F6 + FFFF51ACDEFF358ACAFF358ACAFF358ACBFF348BCDFF5ABDEAFF94BDC4FFAEA6 + 99FFAFA393FFAEA393FFAEA293FFB1A89AFFAFC0C2FF2C6A94C43D92CFFFB8F3 + FFFF77DFFEFF7BE0FEFF7CE1FEFF7CE1FFFF7DE2FFFF50ACE0FF51BBEDFFD3FB + FFFFCFFAFFFFCEF9FFFFCEF9FFFFD0FAFFFFD7FEFFFF3B95D3FF3C92CFFFC0F3 + FFFF70D9FBFF73DAFBFF74DAFBFF74DAFBFF74DBFCFF76DEFDFF4FAADDFF358C + CBFF338CCCFF328CCCFF328DCDFF3690CFFF3C94D0FF2D688FAE3B92CFFFCAF6 + FFFF69D5F9FF6CD5F9FF6AD4F9FF69D4F9FF69D5F9FF6AD6FAFF6BD8FBFF6BD9 + FCFF6BDAFDFF69DAFDFFDAFDFFFF3C93D0FF0A171F2F000000003B92CFFFD5F7 + FFFF60D1F9FF61D0F8FFB4EBFDFFD9F6FFFFDAF8FFFFDAF8FFFFDAF9FFFFDBF9 + FFFFDAF9FFFFDAFAFFFFDFFEFFFF3D94D0FF0E202C35000000003D94D0FFDCFC + FFFFD8F7FFFFD8F7FFFFDBFAFFFF358ECDFF3991CEFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3A92CFFF3D94D0FF3D8BC1EA00000000000000003F8EC5EF3D94 + D0FF3A92CFFF3A92CFFF3D94D0FF3A87BBE40B1A232B0D1E29320E1E2A330E1E + 2A330E1E2A330E1F2A330F212E37000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 0000000000000000002200000033000000330000003300000033000000330000 + 0033000000330000002300000000000000000000000000000000000000000000 + 000A000000258C6839BCCE9956FFCE964EFFAFB4BAFFB1B1B2FFB1B1B1FFB1B1 + B1FFB2B2B2FF7C7C7CBF000000000000000000000000000000000000001F2323 + 205C7E7C77C5D09851FFEDDEBAFFE6CF9FFFFAFCFFFFFAF9FAFFFAF9F9FFFAF9 + F9FFFFFFFFFFB2B2B2FF000000330000002300000000000000006B6760ADB4AF + A4FFC4C1BBFFCE964EFFEBD9B5FFE1C38CFFF0F3F7FFEFF0F0FFEFEFEEFFF0F0 + EFFFF9F9F8FFB0B0B0FFB3B3B3FF7C7C7CBE0000000000000000B1AB9FFFC8C2 + B7FFD0CBC8FFCD954DFFECDAB7FFDEBB7EFFEBECF1FFEAE9E9FFEAE9E8FFEAE9 + E8FFF6F6F5FFADADADFFFFFFFFFFB3B3B3FF0000003300000023B0AB9EFFC8C1 + B8FFCEC9C6FFCC944BFFEFDCBBFFDCB36FFFE5E7EBFFE4E4E3FFE4E3E2FFE5E3 + E2FFF5F5F4FFACACACFFFEFEFCFFB0B1B1FFB3B3B3FF7C7C7CBFB0AA9EFFCAC3 + BAFFECEAE7FFCC944AFFF2E2C3FFF2DEBBFFF6F8FCFFF6F5F5FFF5F4F4FFF5F4 + F4FFF7F6F6FFACACADFFFAFAF9FFAEAEAEFFFFFFFFFFB3B3B3FF6F6B64ADF9F4 + EEFFD8D4CFFFC59F6EFFD09749FFD59843FFB5B7B2FFB3B3ADFFAFAFACFFADAD + ACFFACADADFFC3C3C2FFF8F8F7FFADADADFFFEFEFDFFB2B2B2FF706C64B4A39A + 8FFFBAB3AAFFCCC5BEFFE7E0D3FF1F39DCFF9DAFFFFF98A9FFFFFFFEF7FFFCF9 + F8FFF9F7F7FFF8F7F7FFF8F7F7FFACACADFFFBFBFAFFB2B2B2FFB1AB9FFFC9C2 + B9FFCFC8BFFFD7CEC6FFE5DBCBFF7179D3FF293BD5FF2D39D8FFC3B6B1FFB9B0 + B1FFB1AEAEFFADADADFFADADADFFC3C3C2FFF9F9F8FFB2B2B2FFB0AB9EFFC7C0 + B6FFCCC4BBFFD3CAC1FFDDD3C7FFEDDFD0FFFFF0E0FF009B5AFF79EBD3FF6EE6 + D0FFFFF9FCFFFBF8F9FFF9F8F8FFF9F7F8FFFAF9F9FFB3B3B3FFAFAA9DFFC8C1 + B7FFE8E3DBFFF5F0E8FFFDF9F2FFFFF9F2FFFFFDF6FF4CBC98FF00955FFF0094 + 5CFFB9AFB3FFB0AFB1FFB1B1B2FFB2B2B2FFB3B3B3FF7D7D7DB0AEA89CFFFBF5 + EFFFEEE7DEFFE0D8CEFFDDD5CCFFDDD5CCFFE2D6CEFFEBD9D2FFF1DBD5FFF1DD + D6FFF6E9E1FFFDF7EEFFAEA799FF000000000000000000000000AFA99DFFE1D8 + CEFFE1D7CEFFDFD6CCFFDFD5CBFFDFD5CBFFDFD6CCFFE1D6CCFFE2D6CDFFE2D7 + CDFFE2D8CEFFE2D8CEFFAFA99CFF0000000000000000000000006A675F99B6B0 + A4FFD6CFC4FFE6DED5FFEFE7DDFFEEE6DCFFEEE6DCFFEEE6DCFFEFE7DDFFE6DE + D5FFD6CFC4FFB6B0A4FF6A675F99000000000000000000000000000000002322 + 2033827D74BCAEA99CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA9 + 9CFF827D74BC2322203300000000000000000000000000000000} + end + item + Image.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000000000000000 + 00000000000B0000002200000031000000339F8F96F5A9979CFFA79898FFA49D + 95FFA29F92FFA09F92FF9E9E97FF979A9CFF9498A0FF8C909AF2000000000000 + 00172524215D757169B9AAA498F7AFA99DFF008941FF00E29EFF15EFA7FF2227 + C6FF5E71FFFF7386FFFF1228CBFFFFC963FFFCD086FFBB810BFF000000004F4C + 478DB4ADA2FFC2BBB0FFD0C7BEFFDFD5CDFF008946FF00D49FFF37E8AFFF2A2B + C2FF5A6CFFFF788BFFFF152DCAFFFABC4BFFF4C980FFB78115FF00000000B1AB + 9FFFC7C0B6FFCFC7BEFFD5CCC3FFDBD2C9FF008946FF00C79FFF50E4B9FF2B2C + C1FF4F65FBFF7A8CFFFF172ECBFFF5B033FFF3C67CFFB68217FF00000000B1AB + 9FFFC9C0B8FFCDC5BCFFD4CBC2FFDAD1C8FF008A47FF53EBDDFF69E7C8FF2C2F + C4FF445CF7FF7B8EFCFF172ECCFFF0A218FFF1C479FFB68217FF00000000B0AB + 9EFFC8BFB7FFCBC3BAFFD2C9C0FFD8CFC5FF0F9255FF008B45FF00923AFF3032 + C9FF3B52F3FF7E8FFAFF182ECCFFFBDB7CFFF3C57AFFB88319FF00000000B0AA + 9EFFC9C2B9FFE2DDD4FFF5EFE9FFFFFBF4FFFEFAF3FFFDF9F2FFFDF9F2FF3233 + CBFF2F47EFFF8192F8FF1A30CEFFC68A06FFBB8516FF805C14B0000000006F6B + 64ADF9F4EEFFD7D0C8FFC6BEB6FFBEB5ABFFC2B9AFFFC7BCB4FFC8BEB5FF3135 + CAFF71B4FAFF8798F8FF2035CDFFF9F5EDFF6F6B64AD0000000000000000706C + 64B4A3998FFFB6AEA4FFC8BFB6FFD8CFC7FFE3D9D1FFEADED8FFECE1DAFF676C + CAFF2C3AC1FF2B3AC2FF555FBEFFA49C92FF706C64B40000000000000000B1AB + 9FFFCAC1B9FFCEC7BEFFD5CCC3FFDAD1C8FFE1D7CFFFE8DCD6FFEADFD8FFE2D8 + D1FFDCD2CAFFD6CEC5FFD1C9C0FFCBC4BAFFB1AB9FFF0000000000000000B1AB + 9EFFC8BFB7FFCBC3BAFFD2C8BFFFD8CEC5FFDFD5CDFFE9DED8FFE9DDD6FFE0D6 + CFFFDACFC7FFD3CBC2FFCEC6BDFFC9C2B8FFB0AB9EFF0000000000000000B0AA + 9DFFC7C0B8FFE1DBD2FFF3EDE6FFFDF9F2FFFCF8F1FFFBF7F0FFFBF7F0FFFCF8 + F1FFFDF8F2FFF4EEE6FFE2DBD3FFCAC3B9FFAFAA9DFF0000000000000000AEA8 + 9CFFFBF5EFFFEEE7DEFFE3DCD3FFDDD5CCFFDDD5CBFFDDD4CBFFDDD4CBFFDDD4 + CBFFDDD5CBFFE3DCD3FFEEE7DEFFFBF6EFFFAEA89CFF0000000000000000AFA9 + 9DFFE1D8CEFFE1D8CEFFDFD6CCFFDFD6CBFFDFD5CBFFDFD5CBFFDFD5CBFFDFD5 + CBFFDFD6CBFFDFD6CCFFE1D8CEFFE1D8CEFFAFA99DFF00000000000000004E4C + 4671B6B0A4FFD2CABFFFE2D9D0FFEFE7DDFFEEE6DCFFEEE6DCFFEEE6DCFFEEE6 + DCFFEFE7DDFFE2D9D0FFD2CABFFFB6B0A4FF4E4C467100000000000000000000 + 000025242135747068A8A8A297F5AEA89CFFAEA89CFFAEA89CFFAEA89CFFAEA8 + 9CFFAEA89CFFA8A297F5747068A8252421350000000000000000} + end> + end +end diff --git a/assets/InstructionEditor/Forms/formMain.pas b/assets/InstructionEditor/Forms/formMain.pas new file mode 100644 index 0000000..01bfe89 --- /dev/null +++ b/assets/InstructionEditor/Forms/formMain.pas @@ -0,0 +1,1822 @@ +unit formMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.UITypes, + System.ImageList, System.Generics.Collections, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, + Vcl.ImgList, Vcl.StdCtrls, Vcl.ExtCtrls, dxSkinsCore, dxSkinBlue, dxSkinSeven, dxDockPanel, cxOI, + dxSkinsdxBarPainter, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters,cxVGrid, + dxRibbonCustomizationForm, dxRibbonSkins, cxStyles, cxEdit, cxInplaceContainer, dxSkinsForm, + dxStatusBar, dxRibbonStatusBar, cxClasses, dxRibbon, dxBar, dxRibbonForm, cxSplitter, cxPC, + dxBarExtItems, dxSkinsdxDockControlPainter, dxDockControl, dxSkinsdxRibbonPainter, + dxGDIPlusClasses, VirtualTrees, untInstructionEditor; + +// TODO: Add support for multi node selection and allow copy / paste / cut / delete of mutiple +// definitions +// http://www.delphipraxis.net/136601-virtual-treeview-multiselect-onchange-event-problem.html + +// TODO: Update inspector after inspected object changed + +type + TfrmMain = class(TdxRibbonForm) + BarManager: TdxBarManager; + RibbonTab1: TdxRibbonTab; + Ribbon: TdxRibbon; + StatusBar: TdxRibbonStatusBar; + SkinController: TdxSkinController; + barMainManu: TdxBar; + barEditor: TdxBar; + lbLoadDatabase: TdxBarLargeButton; + lbSaveDatabase: TdxBarLargeButton; + imgIcons16: TcxImageList; + imgIcons32: TcxImageList; + lbCreateDefinition: TdxBarLargeButton; + barStatusBarProgress: TdxBar; + piStatusBarProgress: TdxBarProgressItem; + barView: TdxBar; + Splitter: TcxSplitter; + bbDuplicateDefinition: TdxBarButton; + bbDeleteDefinition: TdxBarButton; + barGenerator: TdxBar; + lbGenerate: TdxBarLargeButton; + pnlInspector: TPanel; + DockingManager: TdxDockingManager; + imgMisc: TcxImageList; + DockSite: TdxDockSite; + LayoutDockSite: TdxLayoutDockSite; + pnlPropertyInspector: TdxDockPanel; + Inspector: TcxRTTIInspector; + pnlPropertyInformation: TdxDockPanel; + VertContainerDockSite: TdxVertContainerDockSite; + lblPropertyInfo: TLabel; + popupEditor: TdxRibbonPopupMenu; + dxBarSeparator1: TdxBarSeparator; + dxBarSeparator2: TdxBarSeparator; + dxBarSeparator3: TdxBarSeparator; + bbClipboardCopy: TdxBarButton; + barClipboard: TdxBar; + lbClipboardPaste: TdxBarLargeButton; + bbClipboardCut: TdxBarButton; + lbMnemonicFilter: TdxBarLargeButton; + bbExpandNodes: TdxBarButton; + bbCollapseNodes: TdxBarButton; + barMnemonicFilter: TdxBar; + edtMnemonicFilter: TdxBarEdit; + bbExactMatch: TdxBarButton; + EditorTree: TVirtualStringTree; + imgTreeView: TcxImageList; + dxBarSeparator4: TdxBarSeparator; + bbExpandLeaf: TdxBarButton; + bbCollapseLeaf: TdxBarButton; + Button1: TButton; + Button2: TButton; + procedure FormCreate(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure lbLoadDatabaseClick(Sender: TObject); + procedure lbSaveDatabaseClick(Sender: TObject); + procedure EditorTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); + procedure EditorTreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure EditorTreeCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; + Column: TColumnIndex; var Result: Integer); + procedure EditorTreeCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; + var Allowed: Boolean); + procedure EditorTreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure lbCreateDefinitionClick(Sender: TObject); + procedure lbGenerateClick(Sender: TObject); + procedure bbDeleteDefinitionClick(Sender: TObject); + procedure InspectorItemChanged(Sender: TObject; AOldRow: TcxCustomRow; AOldCellIndex: Integer); + procedure bbDuplicateDefinitionClick(Sender: TObject); + procedure EditorTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure bbClipboardCopyClick(Sender: TObject); + procedure lbClipboardPasteClick(Sender: TObject); + procedure bbExpandNodesClick(Sender: TObject); + procedure bbCollapseNodesClick(Sender: TObject); + procedure bbClipboardCutClick(Sender: TObject); + procedure lbMnemonicFilterClick(Sender: TObject); + procedure edtMnemonicFilterCurChange(Sender: TObject); + procedure bbExactMatchClick(Sender: TObject); + procedure EditorTreeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, + Y: Integer); + procedure bbExpandLeafClick(Sender: TObject); + procedure bbCollapseLeafClick(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure Button2Click(Sender: TObject); + procedure EditorTreeGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: TImageIndex); + strict private + FEditor: TInstructionEditor; + FUpdating: Boolean; + FHasUnsavedChanges: Boolean; + FExpandedFilterProperties: TList; + FExpandedDefinitionProperties: TList; + FInspectorActiveFilterRow: String; + FInspectorActiveDefinitionRow: String; + FEditing: Boolean; + FEditedNode: PVirtualNode; + strict private + procedure EditorWorkStart(Sender: TObject; MinWorkCount, MaxWorkCount: Integer); + procedure EditorWork(Sender: TObject; WorkCount: Integer); + procedure EditorWorkEnd(Sender: TObject); + procedure EditorBeginUpdate(Sender: TObject); + procedure EditorEndUpdate(Sender: TObject); + procedure EditorFilterCreated(Sender: TObject; Filter: TInstructionFilter); + procedure EditorFilterInserted(Sender: TObject; Filter: TInstructionFilter); + procedure EditorFilterChanged(Sender: TObject; Filter: TInstructionFilter); + procedure EditorFilterRemoved(Sender: TObject; Filter: TInstructionFilter); + procedure EditorFilterDestroyed(Sender: TObject; Filter: TInstructionFilter); + procedure EditorDefinitionCreated(Sender: TObject; Definition: TInstructionDefinition); + procedure EditorDefinitionInserted(Sender: TObject; Definition: TInstructionDefinition); + procedure EditorDefinitionChanged(Sender: TObject; Definition: TInstructionDefinition); + procedure EditorDefinitionRemoved(Sender: TObject; Definition: TInstructionDefinition); + procedure EditorDefinitionDestroyed(Sender: TObject; Definition: TInstructionDefinition); + strict private + function GetTreeNode(const Definition: TInstructionDefinition): PVirtualNode; overload; + function GetTreeNode(const Filter: TInstructionFilter): PVirtualNode; overload; + strict private + procedure SetDefaultWindowPosition; inline; + procedure LoadGUIConfiguration; + procedure SaveGUIConfiguration; + procedure UpdateExpandedProperties; + strict private + procedure UpdateControls; + procedure UpdateStatistic; + strict private + procedure ClipboardPaste(Node: PVirtualNode); + procedure ClipboardCopy(Node: PVirtualNode); + procedure ClipboardCut(Node: PVirtualNode); + procedure DefinitionCreate; + procedure DefinitionDuplicate(Node: PVirtualNode); + procedure DefinitionDelete(Node: PVirtualNode); + procedure ExpandAllNodes(Expanded: Boolean); + procedure ExpandLeaf(Node: PVirtualNode; Expanded: Boolean); + procedure SetMnemonicFilter(const Filter: String; ExactMatch: Boolean); + public + { Public-Deklarationen } + end; + +var + frmMain: TfrmMain; + +implementation + +uses + System.IniFiles, Vcl.Clipbrd, SynCrossPlatformJSON, formCreateDefinition, formGenerator, + untHelperClasses, untPropertyHints, + + System.Math; + +{$R *.dfm} + +type + TEditorNodeType = (ntFilterTable, ntInstructionDefinition); + + PEditorNodeData = ^TEditorNodeData; + TEditorNodeData = record + public + NodeType: TEditorNodeType; + case Integer of + 0: (DataClass: TPersistent); + 1: (Filter: TInstructionFilter); + 2: (Definition: TInstructionDefinition); + end; + +{$REGION 'Code: TreeView related methods'} +function TfrmMain.GetTreeNode(const Definition: TInstructionDefinition): PVirtualNode; +begin + // We are using the "data" property to store the corresponding node pointer + Assert(Assigned(Definition.Data)); + Result := Definition.Data; +end; + +function TfrmMain.GetTreeNode(const Filter: TInstructionFilter): PVirtualNode; +begin + // We are using the "data" property to store the corresponding node pointer + Assert(Assigned(Filter.Data)); + Result := Filter.Data; +end; +{$ENDREGION} + +{$REGION 'Code: TreeView related operations'} +procedure TfrmMain.ClipboardCopy(Node: PVirtualNode); + +procedure SaveToJSON(Filter: TInstructionFilter; JSONArray: PJSONVariantData); +var + I: Integer; + JSONObject: TJSONVariantData; +begin + if (Filter.IsDefinitionContainer) then + begin + for I := 0 to (Filter as TDefinitionContainer).DefinitionCount - 1 do + begin + JSONObject.Init; + (Filter as TDefinitionContainer).Definitions[I].SaveToJSON(@JSONObject); + JSONArray^.AddValue(Variant(JSONObject)); + end; + end else + begin + for I := 0 to Filter.Capacity - 1 do + begin + if (Assigned(Filter.Items[I])) then + begin + SaveToJSON(Filter.Items[I], JSONArray); + end; + end; + end; +end; + +var + NodeData: PEditorNodeData; + JSON, + JSONArray, + JSONObject: TJSONVariantData; +begin + NodeData := EditorTree.GetNodeData(Node); + if (Assigned(NodeData)) then + begin + JSONArray.Init; + if (NodeData^.NodeType = ntInstructionDefinition) then + begin + JSONObject.Init; + NodeData^.Definition.SaveToJSON(@JSONObject); + JSONArray.AddValue(Variant(JSONObject)); + end else + begin + if (Application.MessageBox( + 'You are trying to copy multiple definitions to clipboard. Do you want to continue?', + 'Question', MB_ICONQUESTION or MB_YESNO) <> IdYes) then + begin + Exit; + end; + SaveToJSON(NodeData^.Filter, @JSONArray); + end; + JSON.Init; + JSON.AddNameValue('definitions', Variant(JSONArray)); + Clipboard.AsText := TJSONHelper.JSONToString(@JSON); + end; +end; + +procedure TfrmMain.ClipboardCut(Node: PVirtualNode); +begin + ClipboardCopy(Node); + DefinitionDelete(Node); +end; + +procedure TfrmMain.ClipboardPaste(Node: PVirtualNode); +var + JSON: TJSONVariantData; + JSONArray: PJSONVariantData; + I: Integer; + D: TInstructionDefinition; +begin + JSON.Init; + if (JSON.FromJSON(Clipboard.AsText) and (JSON.Kind = jvObject)) then + begin + JSONArray := JSON.Data('definitions'); + if (Assigned(JSONArray) and (JSONArray^.Kind = jvArray)) then + begin + if (JSONArray^.Count > 1) then + begin + if (Application.MessageBox( + 'You are trying to paste multiple definitions from clipboard. Do you want to continue?', + 'Question', MB_ICONQUESTION or MB_YESNO) <> IdYes) then + begin + Exit; + end; + end; + FEditor.BeginUpdate; + try + for I := 0 to JSONArray^.Count - 1 do + begin + D := FEditor.CreateDefinition('unnamed'); + try + D.BeginUpdate; + try + D.Update; + D.LoadFromJSON(JSONVariantDataSafe(JSONArray^.Item[I], jvObject)); + finally + D.EndUpdate; + end; + except + on E: Exception do + begin + D.Free; + Application.MessageBox(PChar(E.Message), 'Error', MB_ICONERROR); + end; + end; + end; + finally + FEditor.EndUpdate; + end; + end; + end; +end; + +procedure TfrmMain.DefinitionCreate; +var + frmCreateDefinition: TfrmCreateDefinition; + D: TInstructionDefinition; +begin + frmCreateDefinition := TfrmCreateDefinition.Create(Application); + try + D := FEditor.CreateDefinition('unnamed'); + D.BeginUpdate; + try + // Force initial position update to cause OnDefinitionInserted for new definitions with + // unchanged (position-relevant) properties. + D.Update; + frmCreateDefinition.Inspector.InspectedObject := D; + frmCreateDefinition.ShowModal; + finally + if (not frmCreateDefinition.Canceled) then D.EndUpdate; + end; + if (frmCreateDefinition.Canceled) then + begin + D.Free; + end; + finally + frmCreateDefinition.Free; + end; +end; + +procedure TfrmMain.DefinitionDelete(Node: PVirtualNode); +var + NextNode: PVirtualNode; + NodeData: PEditorNodeData; +begin + NodeData := EditorTree.GetNodeData(Node); + if Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition) then + begin + NextNode := EditorTree.GetNextSibling(Node); + if (not Assigned(NextNode)) then + begin + NextNode := EditorTree.GetPreviousSibling(Node); + end; + NodeData^.Definition.Free; + if (Assigned(NextNode)) then + begin + EditorTree.FocusedNode := NextNode; + EditorTree.Selected[NextNode] := true; + end; + end; +end; + +procedure TfrmMain.DefinitionDuplicate(Node: PVirtualNode); +var + frmCreateDefinition: TfrmCreateDefinition; + D: TInstructionDefinition; + NodeData: PEditorNodeData; +begin + NodeData := EditorTree.GetNodeData(Node); + if (Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition)) then + begin + frmCreateDefinition := TfrmCreateDefinition.Create(Application); + try + D := FEditor.CreateDefinition('unnamed'); + D.BeginUpdate; + try + // Force initial position update to cause OnDefinitionInserted for new definitions with + // unchanged (position-relevant) properties. + D.Update; + D.Assign(NodeData^.Definition); + frmCreateDefinition.Inspector.InspectedObject := D; + frmCreateDefinition.ShowModal; + finally + if (not frmCreateDefinition.Canceled) then D.EndUpdate; + end; + if (frmCreateDefinition.Canceled) then + begin + D.Free; + end; + finally + frmCreateDefinition.Free; + end; + end; +end; + +procedure TfrmMain.ExpandAllNodes(Expanded: Boolean); +var + Node: PVirtualNode; + NodeData: PEditorNodeData; +begin + EditorTree.BeginUpdate; + try + Node := EditorTree.GetFirst; + while (Assigned(Node)) do + begin + NodeData := EditorTree.GetNodeData(Node); + if (Assigned(NodeData) and (NodeData^.NodeType = ntFilterTable) and + (Assigned(NodeData^.Filter)) and + (not (iffIsRootTable in NodeData^.Filter.FilterFlags))) then + begin + EditorTree.Expanded[Node] := Expanded; + end; + Node := EditorTree.GetNext(Node); + end; + finally + EditorTree.EndUpdate; + end; +end; + +procedure TfrmMain.ExpandLeaf(Node: PVirtualNode; Expanded: Boolean); +begin + // TODO: +end; +{$ENDREGION} + +{$REGION 'Events: Form'} +procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +var + ID: Integer; +begin + CanClose := true; + if (FHasUnsavedChanges) then + begin + ID := Application.MessageBox('The current database have unsaved changes. Do you' + + ' really want to exit?', 'Question', MB_ICONWARNING or MB_YESNO or MB_DEFBUTTON2); + CanClose := (ID = IdYes); + end; +end; + +procedure TfrmMain.FormCreate(Sender: TObject); +begin + EditorTree.NodeDataSize := SizeOf(TEditorNodeData); + + FExpandedFilterProperties := TList.Create; + FExpandedDefinitionProperties := TList.Create; + + SetDefaultWindowPosition; + LoadGUIConfiguration; + + StatusBar.Panels[1].Visible := false; + + FEditor := TInstructionEditor.Create; + FEditor.OnWorkStart := EditorWorkStart; + FEditor.OnWork := EditorWork; + FEditor.OnWorkEnd := EditorWorkEnd; + FEditor.OnBeginUpdate := EditorBeginUpdate; + FEditor.OnEndUpdate := EditorEndUpdate; + FEditor.OnFilterCreated := EditorFilterCreated; + FEditor.OnFilterInserted := EditorFilterInserted; + FEditor.OnFilterChanged := EditorFilterChanged; + FEditor.OnFilterRemoved := EditorFilterRemoved; + FEditor.OnFilterDestroyed := EditorFilterDestroyed; + FEditor.OnDefinitionCreated := EditorDefinitionCreated; + FEditor.OnDefinitionInserted := EditorDefinitionInserted; + FEditor.OnDefinitionChanged := EditorDefinitionChanged; + FEditor.OnDefinitionRemoved := EditorDefinitionRemoved; + FEditor.OnDefinitionDestroyed := EditorDefinitionDestroyed; + + FEditing := false; + FEditor.Reset; + FEditing := true; + ExpandAllNodes(true); +end; + +procedure TfrmMain.FormDestroy(Sender: TObject); +begin + FEditing := false; + SaveGUIConfiguration; + ExpandAllNodes(false); + if (Assigned(FEditor)) then + begin + FEditor.Free; + end; + if (Assigned(FExpandedFilterProperties)) then + begin + FExpandedFilterProperties.Free; + end; + if (Assigned(FExpandedDefinitionProperties)) then + begin + FExpandedDefinitionProperties.Free; + end; +end; + +procedure TfrmMain.FormResize(Sender: TObject); +begin + piStatusBarProgress.Width := barStatusBarProgress.Control.ClientWidth; +end; +{$ENDREGION} + +{$REGION 'Events: InstructionEditor'} +procedure TfrmMain.EditorBeginUpdate(Sender: TObject); +begin + EditorTree.BeginUpdate; + FUpdating := true; +end; + +procedure TfrmMain.EditorDefinitionChanged(Sender: TObject; Definition: TInstructionDefinition); +begin + EditorTree.RepaintNode(GetTreeNode(Definition)); + UpdateStatistic; + if (FEditing) then + begin + if (not (csDestroying in ComponentState)) and (lbMnemonicFilter.Down) then + begin + SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down); + end; + FHasUnsavedChanges := true; + UpdateControls; + end; +end; + +procedure TfrmMain.EditorDefinitionCreated(Sender: TObject; Definition: TInstructionDefinition); +var + Node: PVirtualNode; + NodeData: PEditorNodeData; +begin + Node := EditorTree.AddChild(nil); + Definition.Data := Node; + EditorTree.IsVisible[Node] := false; + NodeData := EditorTree.GetNodeData(Node); + NodeData^.NodeType := ntInstructionDefinition; + NodeData^.Definition := Definition; + UpdateStatistic; +end; + +procedure TfrmMain.EditorDefinitionDestroyed(Sender: TObject; Definition: TInstructionDefinition); +begin + EditorTree.DeleteNode(GetTreeNode(Definition)); + if (Inspector.InspectedObject = Definition) then + begin + Inspector.InspectedObject := nil; + end; + UpdateStatistic; +end; + +procedure TfrmMain.EditorDefinitionInserted(Sender: TObject; Definition: TInstructionDefinition); +var + Node: PVirtualNode; +begin + Assert(Assigned(Definition.Parent)); + Node := GetTreeNode(Definition); + EditorTree.IsVisible[Node] := true; + EditorTree.MoveTo(Node, GetTreeNode(Definition.Parent), amAddChildLast, false); + if (FEditing) then + begin + FEditedNode := Node; + FHasUnsavedChanges := true; + UpdateControls; + end; +end; + +procedure TfrmMain.EditorDefinitionRemoved(Sender: TObject; Definition: TInstructionDefinition); +var + Node: PVirtualNode; +begin + Node := GetTreeNode(Definition); + EditorTree.IsVisible[Node] := false; + EditorTree.MoveTo(Node, nil, amInsertAfter, false); + if (FEditing) then + begin + if (EditorTree.FocusedNode = Node) then + begin + EditorTree.FocusedNode := nil; + EditorTree.Selected[Node] := false; + end; + FHasUnsavedChanges := true; + UpdateControls; + end; +end; + +procedure TfrmMain.EditorEndUpdate(Sender: TObject); +begin + EditorTree.EndUpdate; + FUpdating := false; + if (FEditing) and Assigned(FEditedNode) then + begin + EditorTree.FocusedNode := FEditedNode; + EditorTree.Selected[FEditedNode] := true; + EditorTree.ScrollIntoView(FEditedNode, true); + FEditedNode := nil; + end; + UpdateStatistic; +end; + +procedure TfrmMain.EditorFilterChanged(Sender: TObject; Filter: TInstructionFilter); +begin + EditorTree.RepaintNode(GetTreeNode(Filter)); +end; + +procedure TfrmMain.EditorFilterCreated(Sender: TObject; Filter: TInstructionFilter); +var + Node: PVirtualNode; + NodeData: PEditorNodeData; +begin + Node := EditorTree.AddChild(nil); + Filter.Data := Node; + if (not (iffIsRootTable in Filter.FilterFlags)) then + begin + EditorTree.IsVisible[Node] := false; + end; + NodeData := EditorTree.GetNodeData(Node); + NodeData^.NodeType := ntFilterTable; + NodeData^.Filter := Filter; + UpdateStatistic; +end; + +procedure TfrmMain.EditorFilterDestroyed(Sender: TObject; Filter: TInstructionFilter); +begin + EditorTree.DeleteNode(GetTreeNode(Filter)); + if (Inspector.InspectedObject = Filter) then + begin + Inspector.InspectedObject := nil; + end; + UpdateStatistic; +end; + +procedure TfrmMain.EditorFilterInserted(Sender: TObject; Filter: TInstructionFilter); +var + Node, ParentNode: PVirtualNode; +begin + Assert(Assigned(Filter.Parent)); + Node := GetTreeNode(Filter); + ParentNode := GetTreeNode(Filter.Parent); + EditorTree.MoveTo(Node, ParentNode, amAddChildLast, false); + EditorTree.IsVisible[Node] := true; + // Expand root table after first filter insertion + if (iffIsRootTable in Filter.Parent.FilterFlags) and (Filter.Parent.ItemCount = 1) then + begin + EditorTree.Expanded[ParentNode] := true; + end; +end; + +procedure TfrmMain.EditorFilterRemoved(Sender: TObject; Filter: TInstructionFilter); +var + Node: PVirtualNode; +begin + Node := GetTreeNode(Filter); + EditorTree.IsVisible[Node] := false; + EditorTree.MoveTo(Node, nil, amInsertAfter, false); + if (FEditing) then + begin + if (EditorTree.FocusedNode = Node) then + begin + EditorTree.FocusedNode := nil; + EditorTree.Selected[Node] := false; + end; + UpdateControls; + end; +end; + +procedure TfrmMain.EditorWork(Sender: TObject; WorkCount: Integer); +begin + piStatusBarProgress.Position := WorkCount; + if ((WorkCount mod piStatusBarProgress.Tag) = 0) then + begin + Application.ProcessMessages; + end; +end; + +procedure TfrmMain.EditorWorkEnd(Sender: TObject); +begin + piStatusBarProgress.Visible := ivNever; +end; + +procedure TfrmMain.EditorWorkStart(Sender: TObject; MinWorkCount, MaxWorkCount: Integer); +begin + piStatusBarProgress.Min := MinWorkCount; + piStatusBarProgress.Max := MaxWorkCount; + piStatusBarProgress.Tag := Round((MaxWorkCount - MinWorkCount) / 100) + 1; + piStatusBarProgress.Position := 0; + piStatusBarProgress.Visible := ivAlways; +end; +{$ENDREGION} + +{$REGION 'Events: TreeView'} +procedure TfrmMain.EditorTreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + NodeData: PEditorNodeData; + I: Integer; +begin + UpdateExpandedProperties; + Inspector.BeginUpdate; + try + if (Assigned(Inspector.FocusedRow)) then + begin + if (Inspector.InspectedObject is TInstructionFilter) then + begin + FInspectorActiveFilterRow := + (Inspector.FocusedRow as TcxPropertyRow).PropertyEditor.GetName; + end else if (Inspector.InspectedObject is TInstructionDefinition) then + begin + FInspectorActiveDefinitionRow := + (Inspector.FocusedRow as TcxPropertyRow).PropertyEditor.GetName; + end; + end; + Inspector.InspectedObject := nil; + NodeData := Sender.GetNodeData(Node); + if Assigned(NodeData) then + begin + Inspector.InspectedObject := NodeData^.DataClass; + for I := 0 to Inspector.Rows.Count - 1 do + begin + if ((NodeData^.NodeType = ntFilterTable) and FExpandedFilterProperties.Contains( + (Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) or + ((NodeData^.NodeType = ntInstructionDefinition) and + FExpandedDefinitionProperties.Contains( + (Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) then + begin + Inspector.Rows[I].Expanded := true; + end; + if ((NodeData^.NodeType = ntFilterTable) and (FInspectorActiveFilterRow = + (Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) or + ((NodeData^.NodeType = ntInstructionDefinition) and + (FInspectorActiveDefinitionRow = + (Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName)) then + begin + Inspector.FocusedRow := Inspector.Rows[I]; + end; + end; + end; + finally + Inspector.EndUpdate; + end; + UpdateControls; +end; + +procedure TfrmMain.EditorTreeCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; + var Allowed: Boolean); +var + NodeData: PEditorNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData) and (NodeData^.NodeType = ntFilterTable) and + Assigned(NodeData^.Filter) and (iffIsRootTable in NodeData^.Filter.FilterFlags)) then + begin + Allowed := false; + end; +end; + +procedure TfrmMain.EditorTreeCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; + Column: TColumnIndex; var Result: Integer); +var + NodeDataA, + NodeDataB: PEditorNodeData; +begin + NodeDataA := Sender.GetNodeData(Node1); + NodeDataB := Sender.GetNodeData(Node2); + if (NodeDataA^.NodeType <> NodeDataB^.NodeType) then Exit; + if (Assigned(NodeDataA) and Assigned(NodeDataB) and + Assigned(NodeDataA^.DataClass) and Assigned(NodeDataB^.DataClass)) then + begin + case NodeDataA^.NodeType of + ntFilterTable: + begin + Assert(NodeDataB^.NodeType = ntFilterTable); + if (Assigned(NodeDataA^.Filter.Parent)) then + begin + Assert(Assigned(NodeDataB^.Filter.Parent)); + Assert(NodeDataA^.Filter.Parent = NodeDataB^.Filter.Parent); + Result := NodeDataA^.Filter.Parent.IndexOf(NodeDataA^.Filter) - + NodeDataB^.Filter.Parent.IndexOf(NodeDataB^.Filter); + end; + end; + ntInstructionDefinition: + begin + Assert(NodeDataB^.NodeType = ntInstructionDefinition); + Result := CompareStr(NodeDataA^.Definition.Mnemonic, NodeDataB^.Definition.Mnemonic); + end; + end; + end; +end; + +procedure TfrmMain.EditorTreeGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: TImageIndex); +var + NodeData: PEditorNodeData; +begin + if (Column <> 0) or (Kind = ikOverlay) then + begin + Exit; + end; + NodeData := Sender.GetNodeData(Node); + if Assigned(NodeData) then + begin + case NodeData^.NodeType of + ntFilterTable: + begin + ImageIndex := 0; + if (NodeData^.Filter is TDefinitionContainer) then + begin + ImageIndex := 1; + end; + end; + ntInstructionDefinition: + begin + ImageIndex := 2; + end; + end; + end; +end; + +procedure TfrmMain.EditorTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + NodeData: PEditorNodeData; + S: String; +begin + CellText := ''; + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData) and Assigned(NodeData^.DataClass)) then + begin + case (NodeData^.NodeType) of + ntFilterTable: + begin + if (TextType <> ttNormal) and (not (Column in [0])) then Exit; + case Column of + 0: + begin + case TextType of + ttNormal: + begin + if (not Assigned(NodeData^.Filter.Parent)) then + begin + CellText := 'Root'; + end else + begin + CellText := IntToHex(NodeData^.Filter.Parent.IndexOf(NodeData^.Filter), 2); + end; + end; + ttStatic: + begin + if (Assigned(NodeData^.Filter.Parent)) then + begin + S := NodeData^.Filter.Parent.GetItemDescription( + NodeData^.Filter.Parent.IndexOf(NodeData^.Filter)); + if (S <> '') then + begin + CellText := '(' + S + ')'; + end; + end; + end; + end; + end; + end; + end; + ntInstructionDefinition: + begin + if (TextType <> ttNormal) and (not (Column in [0, 1])) then Exit; + case Column of + 0: + begin + case TextType of + ttNormal: CellText := IntToHex(Node.Index, 2); + ttStatic: CellText := 'Definition'; + end; + end; + 1: + begin + case TextType of + ttNormal: + begin + CellText := IntToHex(NodeData^.Definition.Opcode, 2); + end; + ttStatic: + begin + CellText := ''; // TODO: + end + end; + end; + 2: CellText := NodeData^.Definition.Mnemonic; + 3: CellText := NodeData^.Definition.Operands.OperandA.GetDescription(true); + 4: CellText := NodeData^.Definition.Operands.OperandB.GetDescription(true); + 5: CellText := NodeData^.Definition.Operands.OperandC.GetDescription(true); + 6: CellText := NodeData^.Definition.Operands.OperandD.GetDescription(true); + 7: CellText := NodeData^.Definition.Comment; + end; + end; + end; + end; +end; + +procedure TfrmMain.EditorTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + +procedure CopyOperands; +var + NodeData: PEditorNodeData; + I: Integer; + S: String; + O: TInstructionOperand; +begin + NodeData := EditorTree.GetNodeData(EditorTree.FocusedNode); + if (Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition)) then + begin + S := ''; + for I := 0 to 3 do + begin + O := nil; + case I of + 0: O := NodeData^.Definition.Operands.OperandA; + 1: O := NodeData^.Definition.Operands.OperandB; + 2: O := NodeData^.Definition.Operands.OperandC; + 3: O := NodeData^.Definition.Operands.OperandD; + end; + S := S + IntToStr(Integer(O.OperandType)) + ',' + IntToStr(Integer(O.Encoding)) + ',' + + IntToStr(Integer(O.AccessMode)) + ','; + end; + Clipboard.AsText := S; + end; +end; + +procedure PasteOperands; +var + NodeData: PEditorNodeData; + A: TArray; + I, J: Integer; + O: TInstructionOperand; +begin + NodeData := EditorTree.GetNodeData(EditorTree.FocusedNode); + if (Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition)) then + begin + A := Clipboard.AsText.Split([',']); + if (Length(A) >= 12) then + begin + I := 0; + J := 0; + while (J < 4) do + begin + O := nil; + case J of + 0: O := NodeData^.Definition.Operands.OperandA; + 1: O := NodeData^.Definition.Operands.OperandB; + 2: O := NodeData^.Definition.Operands.OperandC; + 3: O := NodeData^.Definition.Operands.OperandD; + end; + O.OperandType := TOperandType(StrToInt(A[I])); + O.Encoding := TOperandEncoding(StrToInt(A[I + 1])); + O.AccessMode := TOperandAccessMode(StrToInt(A[I + 2])); + Inc(I, 3); + Inc(J); + end; + end; + end; +end; + +begin + if (ssCtrl in Shift) then + begin + case Key of + Ord('V'): + lbClipboardPaste.Click; + Ord('C'): + bbClipboardCopy.Click; + Ord('X'): + bbClipboardCut.Click; + Ord('F'): + lbMnemonicFilter.Click; + Ord('E'): + CopyOperands; + Ord('R'): + PasteOperands; + end; + end else if (Shift = []) then + begin + case Key of + VK_DELETE: + bbDeleteDefinition.Click; + end; + end; +end; + +procedure TfrmMain.EditorTreeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, + Y: Integer); +begin + if (Button = mbRight) then + begin + popupEditor.PopupFromCursorPos; + end; +end; + +procedure TfrmMain.EditorTreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); +var + NodeData: PEditorNodeData; +begin + NodeData := Sender.GetNodeData(Node); + if (Assigned(NodeData) and Assigned(NodeData^.DataClass)) then + begin + case NodeData^.NodeType of + ntFilterTable: + begin + if (NodeData^.Filter.HasConflicts) then + begin + TargetCanvas.Font.Color := clRed; + Exit; + end; + end; + ntInstructionDefinition: + begin + if (NodeData^.Definition.HasConflicts) then + begin + TargetCanvas.Font.Color := clRed; + Exit; + end; + end; + end; + end; + case Column of + 0: + begin + case TextType of + ttNormal: ; + ttStatic: TargetCanvas.Font.Color := clGray; + end; + end; + 1: + begin + case TextType of + ttNormal: ; + ttStatic: TargetCanvas.Font.Color := clGray; + end; + end; + end; +end; +{$ENDREGION} + +procedure TfrmMain.bbClipboardCopyClick(Sender: TObject); +begin + ClipboardCopy(EditorTree.FocusedNode); +end; + +procedure TfrmMain.bbClipboardCutClick(Sender: TObject); +begin + ClipboardCut(EditorTree.FocusedNode); +end; + +procedure TfrmMain.bbDuplicateDefinitionClick(Sender: TObject); +begin + DefinitionDuplicate(EditorTree.FocusedNode); +end; + +procedure TfrmMain.bbExactMatchClick(Sender: TObject); +begin + SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down); +end; + +procedure TfrmMain.bbExpandLeafClick(Sender: TObject); +begin + ExpandLeaf(EditorTree.FocusedNode, true); +end; + +procedure TfrmMain.bbExpandNodesClick(Sender: TObject); +begin + ExpandAllNodes(true); +end; + +procedure TfrmMain.Button1Click(Sender: TObject); + +procedure DeleteDuplicates(T: TInstructionFilter); +var + L: TList; + D: TInstructionDefinition; + I, J: Integer; + B: Boolean; +begin + if (T is TDefinitionContainer) then + begin + L := TList.Create; + try + for I := (T as TDefinitionContainer).DefinitionCount - 1 downto 0 do + begin + D := (T as TDefinitionContainer).Definitions[I]; + B := true; + for J := 0 to L.Count - 1 do + begin + if ((D.Mnemonic = L[J].Mnemonic) and D.Operands.Equals(L[J].Operands) and + D.CPUID.Equals(L[J].CPUID) and (D.EVEXCD8Scale = L[J].EVEXCD8Scale)) then + begin + L[J].Flags := L[J].Flags + D.Flags; + D.Free; + B := false; + Break; + end; + end; + if (B) then L.Add(D); + end; + finally + L.Free; + end; + end else + begin + for I := 0 to T.Capacity - 1 do + begin + if Assigned(T.Items[I]) then + begin + DeleteDuplicates(T.Items[I]); + end; + end; + end; +end; + +var + I, J, K, RegCount, MemIndex: Integer; + S: String; + A: TArray; + D: TInstructionDefinition; + O: TInstructionOperand; +begin + FEditor.BeginUpdate; + + for I := 0 to FEditor.DefinitionCount - 1 do + begin + D := FEditor.Definitions[I]; + if (D.Encoding <> ieEVEX) then Continue; + S := D.Comment; + J := 1; + while (J < Length(S)) and (S[J] <> ' ') do Inc(J); + Delete(S, 1, J); + A := S.Split([',']); + for J := Low(A) to High(A) do + begin + A[J] := Trim(A[J]); + end; + S := A[High(A)]; + J := 1; + while (J < Length(S)) and (S[J] <> ' ') do Inc(J); + Delete(S, J, Length(S)); + A[High(A)] := S; + if (A[High(A)][1] = '(') then SetLength(A, Length(A) - 1); + + RegCount := 0; + MemIndex := -1; + D.BeginUpdate; + for J := Low(A) to High(A) do + begin + O := nil; + case J of + 0: O := D.Operands.OperandA; + 1: O := D.Operands.OperandB; + 2: O := D.Operands.OperandC; + 3: O := D.Operands.OperandD; + end; + + if (Pos('{1to', A[J]) > 0) then D.Flags := D.Flags + [ifHasEVEXBC]; + if (Pos('{sae}', A[J]) > 0) then D.Flags := D.Flags + [ifHasEVEXSAE]; + + if (Pos('VK1', A[J]) > 0) then O.OperandType := optMSKR; + if (Pos('VK2', A[J]) > 0) then O.OperandType := optMSKR; + if (Pos('VK4', A[J]) > 0) then O.OperandType := optMSKR; + if (Pos('VK8', A[J]) > 0) then O.OperandType := optMSKR; + if (Pos('VK16', A[J]) > 0) then O.OperandType := optMSKR; + if (Pos('VK32', A[J]) > 0) then O.OperandType := optMSKR; + if (Pos('VK64', A[J]) > 0) then O.OperandType := optMSKR; + + if (Pos('GR8', A[J]) > 0) then O.OperandType := optGPR8; + if (Pos('GR16', A[J]) > 0) then O.OperandType := optGPR16; + if (Pos('GR32', A[J]) > 0) then O.OperandType := optGPR32; + if (Pos('GR64', A[J]) > 0) then O.OperandType := optGPR64; + if (Pos('8mem', A[J]) > 0) then O.OperandType := optMem8; + if (Pos('16mem', A[J]) > 0) then O.OperandType := optMem16; + if (Pos('32mem', A[J]) > 0) then + begin + if (Pos('{1to2}', A[J]) > 0) then O.OperandType := optMem32Bcst2 else + if (Pos('{1to4}', A[J]) > 0) then O.OperandType := optMem32Bcst4 else + if (Pos('{1to8}', A[J]) > 0) then O.OperandType := optMem32Bcst8 else + if (Pos('{1to16}', A[J]) > 0) then O.OperandType := optMem32Bcst16 else + O.OperandType := optMem32; + end; + if (Pos('64mem', A[J]) > 0) then + begin + if (Pos('{1to2}', A[J]) > 0) then O.OperandType := optMem64Bcst2 else + if (Pos('{1to4}', A[J]) > 0) then O.OperandType := optMem64Bcst4 else + if (Pos('{1to8}', A[J]) > 0) then O.OperandType := optMem64Bcst8 else + if (Pos('{1to16}', A[J]) > 0) then O.OperandType := optMem64Bcst16 else + O.OperandType := optMem64; + end; + + if (Pos('VR128', A[J]) > 0) then O.OperandType := optVR128; + if (Pos('VR256', A[J]) > 0) then O.OperandType := optVR256; + if (Pos('VR512', A[J]) > 0) then O.OperandType := optVR512; + if (Pos('128mem', A[J]) > 0) then O.OperandType := optMem128; + if (Pos('256mem', A[J]) > 0) then O.OperandType := optMem256; + if (Pos('512mem', A[J]) > 0) then O.OperandType := optMem512; + + if (Pos('vx32', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vx64', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vx128', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vx256', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vx512', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vy32', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vy64', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vy128', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vy256', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vy512', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vz32', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vz64', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vz128', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vz256', A[J]) > 0) then O.Encoding := opeNone; + if (Pos('vz512', A[J]) > 0) then O.Encoding := opeNone; + + if (Pos('imm8', A[J]) > 0) then O.OperandType := optImm8; + if (Pos('imm8u', A[J]) > 0) then O.OperandType := optImm8U; + if (Pos('u8imm', A[J]) > 0) then O.OperandType := optImm8U; + + if (O.Encoding = opeModrmRm) then + begin + MemIndex := J; + if (D.EVEXCD8Scale <> 0) then + begin + case D.EvexCD8Scale of + 1: O.Encoding := opeModrmRmCD1; + 2: O.Encoding := opeModrmRmCD2; + 4: O.Encoding := opeModrmRmCD4; + 8: O.Encoding := opeModrmRmCD8; + 16: O.Encoding := opeModrmRmCD16; + 32: O.Encoding := opeModrmRmCD32; + 64: O.Encoding := opeModrmRmCD64; + end; + end; + end; + + if (O.Encoding = opeModrmReg) then Inc(RegCount); + end; + D.Operands.OperandA.AccessMode := opaWrite; + if (RegCount = 3) or ((RegCount = 2) and (MemIndex > -1) and (MemIndex <> 1)) then + begin + D.Operands.OperandB.Encoding := opeVexVVVV; + end; + D.EndUpdate; + + end; + DeleteDuplicates(FEditor.RootTable.Items[$62]); + FEditor.EndUpdate; +end; + +procedure TfrmMain.Button2Click(Sender: TObject); + +function BitsNeeded(N: Integer): Integer; +begin + Result := Floor(log2(n) + 1); +end; + +var + Mnemonics: TDictionary; + Node: PVirtualNode; + NodeData: PEditorNodeData; + LOPS: TList>; + LCPUID: TList>; + LEFLAGS: TList>; + LREGS: TList>; + I, J, Bits: Integer; + B: Boolean; + POPS: TPair; + PCPUID: TPair; + PEFLAGS: TPair; + PREGS: TPair; +begin + Bits := 4; // EVEX Info + + Mnemonics := TDictionary.Create; + try + Node := EditorTree.GetFirst; + while Assigned(Node) do + begin + NodeData := EditorTree.GetNodeData(Node); + if (NodeData^.NodeType = ntInstructionDefinition) then + begin + if (not Mnemonics.ContainsKey(NodeData^.Definition.Mnemonic)) then + begin + Mnemonics.Add(NodeData^.Definition.Mnemonic, true); + end; + end; + Node := EditorTree.GetNext(Node); + end; + ShowMessage('Mnemonics: ' + IntToStr(Mnemonics.Count) + ' (' + IntToStr(BitsNeeded(Mnemonics.Count)) + ' bit)'); + Inc(Bits, BitsNeeded(Mnemonics.Count)); + finally + Mnemonics.Free; + end; + + LOPS := TList>.Create; + for I := 0 to FEditor.DefinitionCount - 1 do + begin + B := false; + for J := 0 to LOPS.Count - 1 do + begin + if (LOPS[J].Key.Equals(FEditor.Definitions[I].Operands)) then + begin + POPS := LOPS[J]; + Inc(POPS.Value); + LOPS[J] := POPS; + B := true; + Break; + end; + end; + if (not B) then + begin + POPS.Key := FEditor.Definitions[I].Operands; + POPS.Value := 1; + LOPS.Add(POPS); + end; + end; + ShowMessage('OPS: ' + IntToStr(LOPS.Count) + ' (' + IntToStr(BitsNeeded(LOPS.Count)) + ' bit)'); + Inc(Bits, BitsNeeded(LOPS.Count)); + LOPS.Free; + + LCPUID := TList>.Create; + for I := 0 to FEditor.DefinitionCount - 1 do + begin + B := false; + for J := 0 to LOPS.Count - 1 do + begin + if (LCPUID[J].Key = FEditor.Definitions[I].CPUID.FeatureFlags) then + begin + PCPUID := LCPUID[J]; + Inc(PCPUID.Value); + LCPUID[J] := PCPUID; + B := true; + Break; + end; + end; + if (not B) then + begin + PCPUID.Key := FEditor.Definitions[I].CPUID.FeatureFlags; + PCPUID.Value := 1; + LCPUID.Add(PCPUID); + end; + end; + ShowMessage('CPUID: ' + IntToStr(LCPUID.Count) + ' (' + IntToStr(BitsNeeded(LCPUID.Count)) + ' bit)'); + Inc(Bits, BitsNeeded(LCPUID.Count)); + LCPUID.Free; + + LEFLAGS := TList>.Create; + for I := 0 to FEditor.DefinitionCount - 1 do + begin + B := false; + for J := 0 to LOPS.Count - 1 do + begin + if (LEFLAGS[J].Key.Equals(FEditor.Definitions[I].X86Flags)) then + begin + PEFLAGS := LEFLAGS[J]; + Inc(PEFLAGS.Value); + LEFLAGS[J] := PEFLAGS; + B := true; + Break; + end; + end; + if (not B) then + begin + PEFLAGS.Key := FEditor.Definitions[I].X86Flags; + PEFLAGS.Value := 1; + LEFLAGS.Add(PEFLAGS); + end; + end; + ShowMessage('EFLAGS: ' + IntToStr(LEFLAGS.Count) + ' (' + IntToStr(BitsNeeded(LEFLAGS.Count)) + ' bit)'); + Inc(Bits, BitsNeeded(LEFLAGS.Count)); + LEFLAGS.Free; + + LREGS := TList>.Create; + for I := 0 to FEditor.DefinitionCount - 1 do + begin + B := false; + for J := 0 to LOPS.Count - 1 do + begin + if (LREGS[J].Key = FEditor.Definitions[I].ImplicitRead.Registers) then + begin + PREGS := LREGS[J]; + Inc(PREGS.Value); + LREGS[J] := PREGS; + B := true; + Break; + end; + end; + if (not B) then + begin + PREGS.Key := FEditor.Definitions[I].ImplicitRead.Registers; + PREGS.Value := 1; + LREGS.Add(PREGS); + end; + B := false; + for J := 0 to LOPS.Count - 1 do + begin + if (LREGS[J].Key = FEditor.Definitions[I].ImplicitWrite.Registers) then + begin + PREGS := LREGS[J]; + Inc(PREGS.Value); + LREGS[J] := PREGS; + B := true; + Break; + end; + end; + if (not B) then + begin + PREGS.Key := FEditor.Definitions[I].ImplicitWrite.Registers; + PREGS.Value := 1; + LREGS.Add(PREGS); + end; + end; + ShowMessage('REGS: ' + IntToStr(LREGS.Count) + ' (' + IntToStr(BitsNeeded(LREGS.Count)) + ' bit)'); + Inc(Bits, BitsNeeded(LREGS.Count)); + LEFLAGS.Free; + + ShowMessage('BytesNeeded: ' + IntToStr(Ceil(Bits / 8)) + ' (' + IntToStr(Bits) + ' bits)'); +end; + +procedure TfrmMain.bbCollapseLeafClick(Sender: TObject); +begin + ExpandLeaf(EditorTree.FocusedNode, false); +end; + +procedure TfrmMain.bbCollapseNodesClick(Sender: TObject); +begin + ExpandAllNodes(false); +end; + +procedure TfrmMain.bbDeleteDefinitionClick(Sender: TObject); +begin + DefinitionDelete(EditorTree.FocusedNode); +end; + +procedure TfrmMain.edtMnemonicFilterCurChange(Sender: TObject); +begin + // TODO: Filter is offsync, if the user leaves the edit by pressing ESC or focusing an other + // control + SetMnemonicFilter(edtMnemonicFilter.CurText, bbExactMatch.Down); +end; + +procedure TfrmMain.lbClipboardPasteClick(Sender: TObject); +begin + ClipboardPaste(EditorTree.FocusedNode); +end; + +procedure TfrmMain.lbCreateDefinitionClick(Sender: TObject); +begin + DefinitionCreate; +end; + +procedure TfrmMain.lbGenerateClick(Sender: TObject); + +procedure DeleteDuplicates(T: TInstructionFilter); +var + L: TList; + D: TInstructionDefinition; + I, J: Integer; + B: Boolean; +begin + if (T is TDefinitionContainer) then + begin + L := TList.Create; + try + for I := (T as TDefinitionContainer).DefinitionCount - 1 downto 0 do + begin + D := (T as TDefinitionContainer).Definitions[I]; + B := true; + for J := 0 to L.Count - 1 do + begin + if (D.Equals(L[J])) then + begin + D.Free; + B := false; + Break; + end; + end; + if (B) then L.Add(D); + end; + finally + L.Free; + end; + end else + begin + for I := 0 to T.Capacity - 1 do + begin + if Assigned(T.Items[I]) then + begin + DeleteDuplicates(T.Items[I]); + end; + end; + end; +end; + +var + frmGenerator: TfrmGenerator; +begin + frmGenerator := TfrmGenerator.Create(Application); + try + frmGenerator.Editor := FEditor; + frmGenerator.ShowModal; + finally + frmGenerator.Free; + end; + + Exit; + FEditor.BeginUpdate; + DeleteDuplicates(FEditor.RootTable); + FEditor.EndUpdate; +end; + +procedure TfrmMain.lbLoadDatabaseClick(Sender: TObject); +var + ID: Integer; +begin + if (FHasUnsavedChanges) then + begin + ID := Application.MessageBox('Reloading the database will revert all unsaved changes. Do you' + + ' really want to continue?', 'Question', MB_ICONWARNING or MB_YESNO or MB_DEFBUTTON2); + if (ID <> IdYes) then + begin + Exit; + end; + end; + FEditing := false; + try + ExpandAllNodes(false); + FEditor.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'instructions.json'); + if (lbMnemonicFilter.Down) then + begin + SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down); + end; + except + on E: Exception do + begin + Application.MessageBox(PChar(E.Message), 'Error', MB_ICONERROR); + end; + end; + FEditing := true; + FHasUnsavedChanges := false; + UpdateControls; +end; + +procedure TfrmMain.lbMnemonicFilterClick(Sender: TObject); +begin + StatusBar.Panels[1].Visible := lbMnemonicFilter.Down; + piStatusBarProgress.Width := barStatusBarProgress.Control.ClientWidth; + if (lbMnemonicFilter.Down) then + begin + SetMnemonicFilter(edtMnemonicFilter.Text, bbExactMatch.Down); + edtMnemonicFilter.SetFocus; + end else + begin + SetMnemonicFilter('', false); + end; +end; + +procedure TfrmMain.lbSaveDatabaseClick(Sender: TObject); +begin + FEditor.SaveToFile(ExtractFilePath(ParamStr(0)) + 'instructions.json'); + FHasUnsavedChanges := false; + UpdateControls; +end; + +procedure TfrmMain.LoadGUIConfiguration; +var + Ini: TIniFile; + I: Integer; + A: TArray; +begin + DockingManager.LoadLayoutFromIniFile(ChangeFileExt(ParamStr(0), 'Layout.ini')); + Ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini')); + try + for I := 0 to EditorTree.Header.Columns.Count - 1 do + begin + EditorTree.Header.Columns[I].Width := Ini.ReadInteger('Editor', + Format('Col_%.2d_Width', [I]), EditorTree.Header.Columns[I].Width); + end; + A := Ini.ReadString('Inspector', 'ExpandedFilterProperties', '').Split([',']); + for I := Low(A) to High(A) do + begin + FExpandedFilterProperties.Add(A[I]); + end; + A := Ini.ReadString('Inspector', 'ExpandedDefinitionProperties', '').Split([',']); + for I := Low(A) to High(A) do + begin + FExpandedDefinitionProperties.Add(A[I]); + end; + pnlInspector.Width := Ini.ReadInteger('Inspector', 'Width', 364); + Inspector.OptionsView.RowHeaderWidth := Ini.ReadInteger('Inspector', 'RowHeaderWidth', 170); + finally + Ini.Free; + end; +end; + +procedure TfrmMain.SaveGUIConfiguration; +var + Ini: TIniFile; + I: Integer; + S: String; +begin + DockingManager.SaveLayoutToIniFile(ChangeFileExt(ParamStr(0), 'Layout.ini')); + Ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini')); + try + for I := 0 to EditorTree.Header.Columns.Count - 1 do + begin + Ini.WriteInteger('Editor', Format('Col_%.2d_Width', [I]), EditorTree.Header.Columns[I].Width); + end; + UpdateExpandedProperties; + S := ''; + for I := 0 to FExpandedFilterProperties.Count - 1 do + begin + S := S + FExpandedFilterProperties[I]; + if (I < FExpandedFilterProperties.Count - 1) then + begin + S := S + ','; + end; + end; + Ini.WriteString('Inspector', 'ExpandedFilterProperties', S); + S := ''; + for I := 0 to FExpandedDefinitionProperties.Count - 1 do + begin + S := S + FExpandedDefinitionProperties[I]; + if (I < FExpandedDefinitionProperties.Count - 1) then + begin + S := S + ','; + end; + end; + Ini.WriteString('Inspector', 'ExpandedDefinitionProperties', S); + Ini.WriteInteger('Inspector', 'Width', pnlInspector.Width); + Ini.WriteInteger('Inspector', 'RowHeaderWidth', Inspector.OptionsView.RowHeaderWidth); + finally + Ini.Free; + end; +end; + +procedure TfrmMain.SetDefaultWindowPosition; +var + R: TRect; +begin + R := Screen.MonitorFromPoint(Mouse.CursorPos).WorkareaRect; + SetBounds(R.Left + 50, R.Top + 50, R.Width - 100, R.Height - 100); +end; + +procedure TfrmMain.SetMnemonicFilter(const Filter: String; ExactMatch: Boolean); + +procedure ApplyMnemonicFilter(Filter: TInstructionFilter; out IsVisible: Boolean; + const FilterText: String; FilterLength: Integer); +var + D: TInstructionDefinition; + C: TDefinitionContainer; + I: Integer; + B: Boolean; +begin + IsVisible := (FilterLength = 0); + if (iffIsDefinitionContainer in Filter.FilterFlags) then + begin + C := (Filter as TDefinitionContainer); + for I := 0 to C.DefinitionCount - 1 do + begin + B := IsVisible; + D := C.Definitions[I]; + if (not IsVisible) then + begin + if (Length(D.Mnemonic) >= FilterLength) then + begin + if (ExactMatch) then + begin + B := (CompareStr(FilterText, LowerCase(D.Mnemonic)) = 0); + end else + begin + B := (CompareStr(FilterText, AnsiLowerCase(Copy(D.Mnemonic, 1, FilterLength))) = 0); + end; + end; + end; + EditorTree.IsVisible[GetTreeNode(D)] := B; + IsVisible := IsVisible or B; + end; + end else + begin + for I := 0 to Filter.Capacity - 1 do + begin + if (not Assigned(Filter.Items[I])) then Continue; + ApplyMnemonicFilter(Filter.Items[I], B, FilterText, FilterLength); + EditorTree.IsVisible[GetTreeNode(Filter.Items[I])] := B; + IsVisible := IsVisible or B; + end; + EditorTree.IsVisible[GetTreeNode(Filter)] := IsVisible; + end; +end; + +var + FilterText: String; + FilterLength: Integer; + IsVisible: Boolean; +begin + EditorTree.BeginUpdate; + try + FilterText := AnsiLowerCase(Filter); + FilterLength := Length(Filter); + ApplyMnemonicFilter(FEditor.RootTable, IsVisible, FilterText, FilterLength); + finally + EditorTree.EndUpdate; + end; +end; + +procedure TfrmMain.UpdateControls; +var + NodeData: PEditorNodeData; +begin + lbSaveDatabase.Enabled := FHasUnsavedChanges; + + NodeData := EditorTree.GetNodeData(EditorTree.FocusedNode); + bbDuplicateDefinition.Enabled := + Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition); + bbDeleteDefinition.Enabled := + Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition); + bbClipboardCopy.Enabled := + Assigned(NodeData) {and (NodeData^.NodeType = ntInstructionDefinition)}; + bbClipboardCut.Enabled := + Assigned(NodeData) and (NodeData^.NodeType = ntInstructionDefinition); + bbExpandLeaf.Enabled := + Assigned(NodeData) and (NodeData^.NodeType <> ntInstructionDefinition); + bbCollapseLeaf.Enabled := + Assigned(NodeData) and (NodeData^.NodeType <> ntInstructionDefinition); +end; + +procedure TfrmMain.UpdateExpandedProperties; +var + I: Integer; +begin + if (Assigned(Inspector.InspectedObject)) then + begin + if (Inspector.InspectedObject is TInstructionFilter) then + begin + FExpandedFilterProperties.Clear; + end; + if (Inspector.InspectedObject is TInstructionDefinition) then + begin + FExpandedDefinitionProperties.Clear; + end; + for I := 0 to Inspector.Rows.Count - 1 do + begin + if (Inspector.Rows[I].Expanded) then + begin + if (Inspector.InspectedObject is TInstructionFilter) then + begin + FExpandedFilterProperties.Add( + (Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName); + end; + if (Inspector.InspectedObject is TInstructionDefinition) then + begin + FExpandedDefinitionProperties.Add( + (Inspector.Rows[I] as TcxPropertyRow).PropertyEditor.GetName); + end; + end; + end; + end; +end; + +procedure TfrmMain.UpdateStatistic; +var + Mnemonics: TDictionary; + Node: PVirtualNode; + NodeData: PEditorNodeData; +begin + if (not FUpdating) then + begin + Mnemonics := TDictionary.Create; + try + Node := EditorTree.GetFirst; + while Assigned(Node) do + begin + NodeData := EditorTree.GetNodeData(Node); + if (NodeData^.NodeType = ntInstructionDefinition) then + begin + if (not Mnemonics.ContainsKey(NodeData^.Definition.Mnemonic)) then + begin + Mnemonics.Add(NodeData^.Definition.Mnemonic, true); + end; + end; + Node := EditorTree.GetNext(Node); + end; + StatusBar.Panels[2].Text := 'Mnemonics: ' + IntToStr(Mnemonics.Count); + finally + Mnemonics.Free; + end; + StatusBar.Panels[3].Text := 'Definitions: ' + IntToStr(FEditor.DefinitionCount); + StatusBar.Panels[4].Text := 'Filters: ' + IntToStr(FEditor.FilterCount); + end; +end; + +procedure TfrmMain.InspectorItemChanged(Sender: TObject; AOldRow: TcxCustomRow; + AOldCellIndex: Integer); +var + Row: TcxPropertyRow; + S: String; +begin + lblPropertyInfo.Caption := 'No info text available'; + Row := (Inspector.FocusedRow as TcxPropertyRow); + if Assigned(Row) and Assigned(Row.PropertyEditor) then + begin + S := Row.PropertyEditor.GetName; + while (Assigned(Row.Parent)) do + begin + Row := (Row.Parent as TcxPropertyRow); + S := Row.PropertyEditor.GetName + '.' + S; + end; + if (Inspector.InspectedObject is TInstructionFilter) then + begin + S := 'Filter.' + S; + end else if (Inspector.InspectedObject is TInstructionDefinition) then + begin + S := 'Definition.' + S; + end; + lblPropertyInfo.Caption := GetPropertyHint(S); + end; +end; + +end. diff --git a/assets/InstructionEditor/InstructionEditor.dpr b/assets/InstructionEditor/InstructionEditor.dpr new file mode 100644 index 0000000..a0a8f88 --- /dev/null +++ b/assets/InstructionEditor/InstructionEditor.dpr @@ -0,0 +1,29 @@ +program InstructionEditor; + +uses + Vcl.Forms, + formMain in 'Forms\formMain.pas' {frmMain}, + untInstructionEditor in 'untInstructionEditor.pas', + untInstructionFilters in 'untInstructionFilters.pas', + untHelperClasses in 'untHelperClasses.pas', + formEditorCPUIDFeatureFlags in 'Forms\Editors\formEditorCPUIDFeatureFlags.pas' {frmEditorCPUIDFeatureFlags}, + Vcl.Themes, + Vcl.Styles, + untPropertyHints in 'untPropertyHints.pas', + formCreateDefinition in 'Forms\formCreateDefinition.pas' {frmCreateDefinition}, + untPropertyEditors in 'untPropertyEditors.pas', + formEditorX86Registers in 'Forms\Editors\formEditorX86Registers.pas' {frmEditorX86Registers}, + formGenerator in 'Forms\formGenerator.pas' {frmGenerator}, + formEditorInstructionOperands in 'Forms\Editors\formEditorInstructionOperands.pas' {frmEditorInstructionOperands}; + +{$R *.res} + +begin + {$IFDEF DEBUG} + ReportMemoryLeaksOnShutdown := true; + {$ENDIF} + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TfrmMain, frmMain); + Application.Run; +end. diff --git a/assets/InstructionEditor/InstructionEditor.dproj b/assets/InstructionEditor/InstructionEditor.dproj new file mode 100644 index 0000000..d780d2f --- /dev/null +++ b/assets/InstructionEditor/InstructionEditor.dproj @@ -0,0 +1,593 @@ + + + {33BB8B7D-4980-458D-8786-1256495555AE} + 18.1 + VCL + InstructionEditor.dpr + True + Debug + Win32 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + 1031 + $(BDS)\bin\default_app.manifest + CompanyName=zYantific.com;FileDescription=Instruction Definition Editor;FileVersion=1.0.0.0;InternalName=;LegalCopyright=Copyright © 2015 by zYantific.com;LegalTrademarks=;OriginalFilename=;ProductName=Instruction Definition Editor;ProductVersion=1.0.0.0;Comments= + InstructionEditor + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + true + InstructionEditor.ico + true + dxBarRS22;JvGlobus;JvMM;JvManagedThreads;dxSkinsdxRibbonPainterRS22;dxSkinOffice2010BlackRS22;FireDACPgDriver;dxPScxVGridLnkRS22;JvCrypt;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;JvNet;dxWizardControlRS22;JvDotNetCtrls;DbxCommonDriver;vclimg;dbxcds;dxServerModeRS22;DatasnapConnectorsFreePascal;appanalytics;JvXPCtrls;vcldb;dxSkinDarkRoomRS22;dxSkinSilverRS22;dxGDIPlusRS22;CustomIPTransport;dxSkinOffice2010SilverRS22;dsnap;IndyIPServer;IndyCore;dxSkinSummer2008RS22;CloudService;dxSkinLondonLiquidSkyRS22;FireDACIBDriver;JvDB;JvRuntimeDesign;tmsdXE7;dxPScxPivotGridLnkRS22;dxComnRS22;cxPivotGridChartRS22;dsnapxml;dxSpellCheckerRS22;JclDeveloperTools;FireDACDb2Driver;dxPScxGridLnkRS22;dxPScxPCProdRS22;dxSkinVS2010RS22;dxorgcRS22;dxBarExtItemsRS22;dxRibbonRS22;dxSkinsdxBarPainterRS22;dxCoreRS22;cxVerticalGridRS22;bindcompfmx;dxSkinStardustRS22;dxSkinSevenClassicRS22;dxSkinsCoreRS22;dxSpreadSheetRS22;FireDACODBCDriver;RESTBackendComponents;cxSchedulerRS22;dbrtl;dxSkinDevExpressStyleRS22;FireDACCommon;bindcomp;inetdb;cxExportRS22;JvPluginSystem;dxSkinOffice2007BlackRS22;dxSkinXmas2008BlueRS22;dxSkinCoffeeRS22;DBXOdbcDriver;dxSkinscxSchedulerPainterRS22;ibmonitor;vclFireDAC;JvCmp;JvTimeFramework;xmlrtl;ibxpress;dxSkinOffice2013WhiteRS22;dxPSdxDBOCLnkRS22;cxDataRS22;FireDACCommonDriver;cxBarEditItemRS22;soaprtl;bindengine;vclactnband;bindcompvcl;dxBarExtDBItemsRS22;dxSkinOffice2010BlueRS22;Jcl;vclie;dxPSdxDBTVLnkRS22;cxPageControlRS22;dxPsPrVwAdvRS22;FireDACMSSQLDriver;DBXInformixDriver;dxSkinPumpkinRS22;dxSkinFoggyRS22;cxEditorsRS22;dxPScxExtCommonRS22;DataSnapServerMidas;dsnapcon;DBXFirebirdDriver;tmsexdXE7;inet;dxPSPrVwRibbonRS22;dxMapControlRS22;dxSkinSharpRS22;dxmdsRS22;JvPascalInterpreter;FireDACMySQLDriver;soapmidas;vclx;dxSkinOffice2007GreenRS22;dxSkinMetropolisDarkRS22;DBXSybaseASADriver;dxDockingRS22;RESTComponents;dxTabbedMDIRS22;dxdborRS22;dxSkinMoneyTwinsRS22;dbexpress;dxPScxTLLnkRS22;IndyIPClient;dxSkinSpringTimeRS22;FireDACTDataDriver;FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;dxSkinHighContrastRS22;dxSkinOffice2007SilverRS22;fmx;dxPSdxFCLnkRS22;JvDlgs;IndySystem;dxLayoutControlRS22;dxSkinOffice2007PinkRS22;tethering;cxSchedulerGridRS22;dxSkinMcSkinRS22;vclib;DataSnapClient;dxSkinsdxNavBarPainterRS22;dxNavBarRS22;DataSnapProviderClient;DBXSybaseASEDriver;dxSkinGlassOceansRS22;dxSkinBlueprintRS22;dxSkinBlueRS22;vcldsnap;dxBarDBNavRS22;dxSkiniMaginaryRS22;dxPSCoreRS22;dxSkinLiquidSkyRS22;fmxFireDAC;DBXDb2Driver;dxSkinOffice2007BlueRS22;dxSkinCaramelRS22;DBXOracleDriver;cxGridRS22;JvCore;vclribbon;fmxase;vcl;DBXMSSQLDriver;IndyIPCommon;dxThemeRS22;DataSnapFireDAC;FireDACDBXDriver;dxPScxSchedulerLnkRS22;JvAppFrm;soapserver;cxPivotGridRS22;dxtrmdRS22;dxSkinscxPCPainterRS22;inetdbxpress;FireDACInfxDriver;JvDocking;adortl;tmswizdXE7;cxLibraryRS22;dxPSdxSpreadSheetLnkRS22;JvWizards;dxFireDACServerModeRS22;dxPSdxLCLnkRS22;FireDACASADriver;dxSkinOffice2013DarkGrayRS22;JvHMI;dxPScxCommonRS22;JvBands;emsclientfiredac;rtl;DbxClientDriver;dxSkinOffice2013LightGrayRS22;JclContainers;dxFlowChartRS22;dxPSLnksRS22;dxSkinSharpPlusRS22;dxSkinDarkSideRS22;JvSystem;DataSnapNativeClient;svnui;cxTreeListdxBarPopupMenuRS22;JvControls;dxSkinsdxDLPainterRS22;dxSkinValentineRS22;IndyProtocols;DBXMySQLDriver;dxSkinDevExpressDarkStyleRS22;dxPSdxOCLnkRS22;dxSkinMetropolisRS22;bindcompdbx;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;cxTreeListRS22;dxSkinTheAsphaltWorldRS22;FireDACADSDriver;vcltouch;dxADOServerModeRS22;emsclient;dxdbtrRS22;VclSmp;FireDAC;VCLRESTComponents;dxTileControlRS22;cxSchedulerRibbonStyleEventEditorRS22;dxSkinSevenRS22;DataSnapConnectors;dxSkinBlackRS22;fmxobj;JclVcl;dxSkinWhiteprintRS22;tmsxlsdXE7;cxPivotGridOLAPRS22;svn;cxSchedulerTreeBrowserRS22;FireDACOracleDriver;fmxdae;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;$(DCC_UsePackage) + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + + + true + true + InstructionEditor.ico + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + true + dxBarRS22;dxSkinsdxRibbonPainterRS22;dxSkinOffice2010BlackRS22;FireDACPgDriver;dxPScxVGridLnkRS22;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxWizardControlRS22;DbxCommonDriver;vclimg;dbxcds;dxServerModeRS22;DatasnapConnectorsFreePascal;appanalytics;vcldb;dxSkinDarkRoomRS22;dxSkinSilverRS22;dxGDIPlusRS22;CustomIPTransport;dxSkinOffice2010SilverRS22;dsnap;IndyIPServer;IndyCore;dxSkinSummer2008RS22;CloudService;dxSkinLondonLiquidSkyRS22;FireDACIBDriver;tmsdXE7;dxPScxPivotGridLnkRS22;dxComnRS22;cxPivotGridChartRS22;dsnapxml;dxSpellCheckerRS22;FireDACDb2Driver;dxPScxGridLnkRS22;dxPScxPCProdRS22;dxSkinVS2010RS22;dxorgcRS22;dxBarExtItemsRS22;dxRibbonRS22;dxSkinsdxBarPainterRS22;dxCoreRS22;cxVerticalGridRS22;bindcompfmx;dxSkinStardustRS22;dxSkinSevenClassicRS22;dxSkinsCoreRS22;dxSpreadSheetRS22;FireDACODBCDriver;RESTBackendComponents;cxSchedulerRS22;dbrtl;dxSkinDevExpressStyleRS22;FireDACCommon;bindcomp;inetdb;cxExportRS22;dxSkinOffice2007BlackRS22;dxSkinXmas2008BlueRS22;dxSkinCoffeeRS22;DBXOdbcDriver;dxSkinscxSchedulerPainterRS22;ibmonitor;vclFireDAC;xmlrtl;ibxpress;dxSkinOffice2013WhiteRS22;dxPSdxDBOCLnkRS22;cxDataRS22;FireDACCommonDriver;cxBarEditItemRS22;soaprtl;bindengine;vclactnband;bindcompvcl;dxBarExtDBItemsRS22;dxSkinOffice2010BlueRS22;vclie;dxPSdxDBTVLnkRS22;cxPageControlRS22;dxPsPrVwAdvRS22;FireDACMSSQLDriver;DBXInformixDriver;dxSkinPumpkinRS22;dxSkinFoggyRS22;cxEditorsRS22;dxPScxExtCommonRS22;DataSnapServerMidas;dsnapcon;DBXFirebirdDriver;tmsexdXE7;inet;dxPSPrVwRibbonRS22;dxMapControlRS22;dxSkinSharpRS22;dxmdsRS22;FireDACMySQLDriver;soapmidas;vclx;dxSkinOffice2007GreenRS22;dxSkinMetropolisDarkRS22;DBXSybaseASADriver;dxDockingRS22;RESTComponents;dxTabbedMDIRS22;dxdborRS22;dxSkinMoneyTwinsRS22;dbexpress;dxPScxTLLnkRS22;IndyIPClient;dxSkinSpringTimeRS22;FireDACTDataDriver;FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;dxSkinHighContrastRS22;dxSkinOffice2007SilverRS22;fmx;dxPSdxFCLnkRS22;IndySystem;dxLayoutControlRS22;dxSkinOffice2007PinkRS22;tethering;cxSchedulerGridRS22;dxSkinMcSkinRS22;vclib;DataSnapClient;dxSkinsdxNavBarPainterRS22;dxNavBarRS22;DataSnapProviderClient;DBXSybaseASEDriver;dxSkinGlassOceansRS22;dxSkinBlueprintRS22;dxSkinBlueRS22;vcldsnap;dxBarDBNavRS22;dxSkiniMaginaryRS22;dxPSCoreRS22;dxSkinLiquidSkyRS22;fmxFireDAC;DBXDb2Driver;dxSkinOffice2007BlueRS22;dxSkinCaramelRS22;DBXOracleDriver;cxGridRS22;vclribbon;fmxase;vcl;DBXMSSQLDriver;IndyIPCommon;dxThemeRS22;DataSnapFireDAC;FireDACDBXDriver;dxPScxSchedulerLnkRS22;soapserver;cxPivotGridRS22;dxtrmdRS22;dxSkinscxPCPainterRS22;inetdbxpress;FireDACInfxDriver;adortl;cxLibraryRS22;dxPSdxSpreadSheetLnkRS22;dxFireDACServerModeRS22;dxPSdxLCLnkRS22;FireDACASADriver;dxSkinOffice2013DarkGrayRS22;dxPScxCommonRS22;emsclientfiredac;rtl;DbxClientDriver;dxSkinOffice2013LightGrayRS22;dxFlowChartRS22;dxPSLnksRS22;dxSkinSharpPlusRS22;dxSkinDarkSideRS22;DataSnapNativeClient;cxTreeListdxBarPopupMenuRS22;dxSkinsdxDLPainterRS22;dxSkinValentineRS22;IndyProtocols;DBXMySQLDriver;dxSkinDevExpressDarkStyleRS22;dxPSdxOCLnkRS22;dxSkinMetropolisRS22;bindcompdbx;cxTreeListRS22;dxSkinTheAsphaltWorldRS22;FireDACADSDriver;vcltouch;dxADOServerModeRS22;emsclient;dxdbtrRS22;VclSmp;FireDAC;VCLRESTComponents;dxTileControlRS22;cxSchedulerRibbonStyleEventEditorRS22;dxSkinSevenRS22;DataSnapConnectors;dxSkinBlackRS22;fmxobj;dxSkinWhiteprintRS22;cxPivotGridOLAPRS22;cxSchedulerTreeBrowserRS22;FireDACOracleDriver;fmxdae;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + true + true + true + 1033 + false + + + DatabaseEditor.ico + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + false + true + 3 + true + true + 1033 + + + true + 1033 + true + + + + MainSource + + +
frmMain
+ dfm +
+ + + + +
frmEditorCPUIDFeatureFlags
+ dfm +
+ + +
frmCreateDefinition
+ dfm +
+ + +
frmEditorX86Registers
+ dfm +
+ +
frmGenerator
+ dfm +
+ +
frmEditorInstructionOperands
+ dfm +
+ + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + InstructionEditor.dpr + + + Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver + Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server + + + + + + InstructionEditor.exe + true + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 1 + + + 1 + + + + + + + + + + + + + True + True + + + 12 + + + + +
diff --git a/assets/InstructionEditor/InstructionEditor.ico b/assets/InstructionEditor/InstructionEditor.ico new file mode 100644 index 0000000..608e7c9 Binary files /dev/null and b/assets/InstructionEditor/InstructionEditor.ico differ diff --git a/assets/InstructionEditor/InstructionEditor.res b/assets/InstructionEditor/InstructionEditor.res new file mode 100644 index 0000000..c485239 Binary files /dev/null and b/assets/InstructionEditor/InstructionEditor.res differ diff --git a/assets/InstructionEditor/InstructionEditor.skincfg b/assets/InstructionEditor/InstructionEditor.skincfg new file mode 100644 index 0000000..6c5c255 --- /dev/null +++ b/assets/InstructionEditor/InstructionEditor.skincfg @@ -0,0 +1,55 @@ +[ExpressSkins] +Default=1 +ShowNotifications=1 +Enabled=1 +dxSkinBlack=0 +dxSkinBlue=0 +dxSkinBlueprint=0 +dxSkinCaramel=0 +dxSkinCoffee=0 +dxSkinDarkRoom=0 +dxSkinDarkSide=0 +dxSkinDevExpressDarkStyle=0 +dxSkinDevExpressStyle=0 +dxSkinFoggy=0 +dxSkinGlassOceans=0 +dxSkinHighContrast=0 +dxSkiniMaginary=0 +dxSkinLiquidSky=0 +dxSkinLondonLiquidSky=0 +dxSkinMcSkin=0 +dxSkinMetropolis=0 +dxSkinMetropolisDark=0 +dxSkinMoneyTwins=0 +dxSkinOffice2007Black=0 +dxSkinOffice2007Blue=0 +dxSkinOffice2007Green=0 +dxSkinOffice2007Pink=0 +dxSkinOffice2007Silver=0 +dxSkinOffice2010Black=0 +dxSkinOffice2010Blue=0 +dxSkinOffice2010Silver=0 +dxSkinOffice2013DarkGray=0 +dxSkinOffice2013LightGray=0 +dxSkinOffice2013White=0 +dxSkinPumpkin=0 +dxSkinSeven=1 +dxSkinSevenClassic=0 +dxSkinSharp=0 +dxSkinSharpPlus=0 +dxSkinSilver=0 +dxSkinSpringTime=0 +dxSkinStardust=0 +dxSkinSummer2008=0 +dxSkinTheAsphaltWorld=0 +dxSkinsDefaultPainters=0 +dxSkinValentine=0 +dxSkinVS2010=0 +dxSkinWhiteprint=0 +dxSkinXmas2008Blue=0 +dxSkinLilian=0 +dxSkinOffice2016Colorful=0 +dxSkinOffice2016Dark=0 +dxSkinVisualStudio2013Blue=0 +dxSkinVisualStudio2013Dark=0 +dxSkinVisualStudio2013Light=0 diff --git a/assets/InstructionEditor/README.md b/assets/InstructionEditor/README.md new file mode 100644 index 0000000..960e84d --- /dev/null +++ b/assets/InstructionEditor/README.md @@ -0,0 +1,26 @@ +Zydis Instruction Editor +======================== + +The Zydis Instruction Editor was created to easily edit the Zydis instruction database. + +:warning: A standalone table-generator written in Phython is on our todo-list and will be released soon. + +## Features ## + +- Shows all instruction definitions in an opcode tree. +- Provides an graphical interface with the functionality to add, change or remove instruction definitions. +- Compiles the instruction definitions into optimized disassembler-tables which are used by the Zyan Disassembler Engine (Zydis). + +## Screenshot ## + +![Zydis Instruction Editor](/screenshot.png?raw=true "Zydis Instruction Editor") + +## Compilation ## + +The Zydis Instruction Editor requires a minimum version of Delphi XE8 and the following third-party component packages: +- VirtualTreeView +- DevExpress VCL Controls (commercial) + +## License ## + +The Zydis Instruction Editor is licensed under the MIT License. Dependencies are under their respective licenses. diff --git a/assets/InstructionEditor/SynCrossPlatform.inc b/assets/InstructionEditor/SynCrossPlatform.inc new file mode 100644 index 0000000..4b485b7 --- /dev/null +++ b/assets/InstructionEditor/SynCrossPlatform.inc @@ -0,0 +1,129 @@ + +{ + This file is part of Synopse mORMot framework. + + Synopse mORMot framework. Copyright (C) 2016 Arnaud Bouchez + Synopse Informatique - http://synopse.info + + *** BEGIN LICENSE BLOCK ***** + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL + + 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. + + The Original Code is Synopse mORMot framework. + + The Initial Developer of the Original Code is Arnaud Bouchez. + + Portions created by the Initial Developer are Copyright (C) 2016 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + + ***** END LICENSE BLOCK ***** + + + Version 1.18 + - first public release, corresponding to mORMot Framework 1.18 + +} + +{$ifdef FPC} + + {.$MODE DELPHI} // we need e.g. auto-dereferenced pointers, as in Delphi + {$INLINE ON} + {$MINENUMSIZE 1} + {$PACKSET 1} + {$PACKENUM 1} + + {$define HASINLINE} + {$define USEOBJECTINSTEADOFRECORD} + {$Q-} // disable overflow checking + {$R-} // disable range checking + + {$ifdef VER2_7_1} + {$define ISFPC271} + // defined if the http://mantis.freepascal.org/view.php?id=26773 bug is fixed + // you should use 2.7.1/trunk branch in revision 28995 from 2014-11-05T22:17:54 + // => this will change the TInvokeableVariantType.SetProperty() signature + {$define FPC_VARIANTSETVAR} + {$endif} + +{$else} + +{$ifdef DWSSCRIPT} // always defined since SMS 1.1.2 + {$define ISDWS} // e.g. for SmartMobileStudio or Delphi Web Script + {$define ISSMS} // for SmartMobileStudio +{$else} + {$ifdef NEXTGEN} + {$define HASINLINE} + {$ZEROBASEDSTRINGS OFF} // we expect to share code among platforms + {$define ISDELPHI2010} + {$define ISDELPHIXE} + {$define USETMONITOR} + {$if CompilerVersion >= 29.0} + {$define ISDELPHIXE8} // e.g. for System.Net.HttpClient + {$ifend} + {$else} + {$ifdef CONDITIONALEXPRESSIONS} // Delphi 6 or newer + {$ifdef UNICODE} + {$ifdef CPUX64} + {$define CPU64} + {$endif} + {$else} + {$define USEOBJECTINSTEADOFRECORD} + {$endif} + {$ifdef VER140} + {$define ISDELPHI6} + {$endif} + {$if CompilerVersion >= 18} // Delphi 2006 or newer + {$define HASINLINE} + {$ifend} + {$if CompilerVersion >= 21.0} + {$define ISDELPHI2010} + {$ifend} + {$if CompilerVersion >= 22.0} + {$define ISDELPHIXE} + {$ifend} + {$if CompilerVersion >= 23.0} + {$define ISDELPHIXE2} // e.g. for Vcl.Graphics + {$ifndef MSWINDOWS} + {$define USETMONITOR} + {$endif} + {$ifend} + {$if CompilerVersion >= 25.0} + {$define ISDELPHIXE4} + {$ZEROBASEDSTRINGS OFF} // we expect to share code among platforms + {$warn DUPLICATE_CTOR_DTOR OFF} // avoid W1029 unneeded hints + {$ifend} + {$if CompilerVersion >= 29.0} + {$define ISDELPHIXE8} // e.g. for System.Net.HttpClient + {$ifend} + {$else} + {$define ISDELPHI5OROLDER} + {$define USEOBJECTINSTEADOFRECORD} + {$endif CONDITIONALEXPRESSIONS} + {$endif NEXTGEN} + {$Q-} // disable overflow checking + {$R-} // disable range checking +{$endif DELPHIWEBSCRIPT} + +{$endif FPC} diff --git a/assets/InstructionEditor/SynCrossPlatformJSON.pas b/assets/InstructionEditor/SynCrossPlatformJSON.pas new file mode 100644 index 0000000..04fc928 --- /dev/null +++ b/assets/InstructionEditor/SynCrossPlatformJSON.pas @@ -0,0 +1,2150 @@ +/// minimum standand-alone cross-platform JSON process using variants +// - this unit is a part of the freeware Synopse mORMot framework, +// licensed under a MPL/GPL/LGPL tri-license; version 1.18 +unit SynCrossPlatformJSON; + +{ + This file is part of Synopse mORMot framework. + + Synopse mORMot framework. Copyright (C) 2016 Arnaud Bouchez + Synopse Informatique - http://synopse.info + + *** BEGIN LICENSE BLOCK ***** + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL + + 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. + + The Original Code is Synopse mORMot framework. + + The Initial Developer of the Original Code is Arnaud Bouchez. + + Portions created by the Initial Developer are Copyright (C) 2016 + the Initial Developer. All Rights Reserved. + + Contributor(s): + - Witya + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + + ***** END LICENSE BLOCK ***** + + + Version 1.18 + - first public release, corresponding to mORMot Framework 1.18 + - would compile with Delphi for any platform (including NextGen for mobiles), + with FPC 2.7 or Kylix, and with SmartMobileStudio 2+ + - FPC prior to 2.7.1 has some issues with working with variants: UTF-8 + encoding is sometimes lost, and TInvokeableVariantType.SetProperty is broken + +} + +{$i SynCrossPlatform.inc} // define e.g. HASINLINE + +interface + +uses + SysUtils, + Classes, +{$ifdef NEXTGEN} + System.Generics.Collections, +{$else} + Contnrs, +{$endif} + Variants, + TypInfo; + +type + TStringDynArray = array of string; + TVariantDynArray = array of variant; + TIntegerDynArray = array of integer; + + /// this type is used to store BLOB content + TByteDynArray = array of byte; + PByteDynArray = ^TByteDynArray; + + {$ifndef UNICODE} + {$ifdef FPC} + NativeInt = PtrInt; + NativeUInt = PtrUInt; + {$else} + NativeInt = integer; + NativeUInt = cardinal; + {$endif} + RawByteString = AnsiString; + {$endif} + + // this type will store UTF-8 encoded buffer (also on NextGen platform) + {$ifdef NEXTGEN} + TUTF8Buffer = TBytes; + // TObjecTList is not defined in Mobile platforms + TObjectList = TObjectList; + {$else} + TUTF8Buffer = UTF8String; + {$endif} + + /// exception used during standand-alone cross-platform JSON process + EJSONException = class(Exception); + + /// which kind of document the TJSONVariantData contains + TJSONVariantKind = (jvUndefined, jvObject, jvArray); + + PJSONVariantData = ^TJSONVariantData; + + {$A-} + /// stores any JSON object or array as variant + // - this structure is not very optimized for speed or memory use, but is + // simple and strong enough for our client-side purpose + // - it is in fact already faster (and using less memory) than DBXJSON and + // SuperObject / XSuperObject libraries - of course, mORMot's TDocVariant + // is faster, as dwsJSON is in some cases, but those are not cross-platform + {$ifdef UNICODE} + TJSONVariantData = record + private + {$else} + TJSONVariantData = object + protected + {$endif} + VType: TVarType; + _Align: byte; + VKind: TJSONVariantKind; + VCount: integer; + function GetKind: TJSONVariantKind; + function GetCount: integer; + function GetVarData(const aName: string; var Dest: TVarData): boolean; + function GetValue(const aName: string): variant; + function GetValueCopy(const aName: string): variant; + procedure SetValue(const aName: string; const aValue: variant); + function GetItem(aIndex: integer): variant; + procedure SetItem(aIndex: integer; const aItem: variant); + public + /// names of this jvObject + Names: TStringDynArray; + /// values of this jvObject or jvArray + Values: TVariantDynArray; + /// initialize the low-level memory structure + procedure Init; overload; + /// initialize the low-level memory structure with a given JSON content + procedure Init(const JSON: string); overload; + /// initialize the low-level memory structure with a given array of variant + procedure InitFrom(const aValues: TVariantDynArray); overload; + /// access to a nested TJSONVariantData item + // - returns nil if aName was not found, or not a true TJSONVariantData item + function Data(const aName: string): PJSONVariantData; + {$ifdef HASINLINE}inline;{$endif} + /// access to a nested TJSONVariantData item, creating it if necessary + // - aPath can be specified with any depth, e.g. 'level1.level2.level3' + // - if the item does not exist or is not a true TJSONVariantData, a new + // one will be created, and returned as pointer + function EnsureData(const aPath: string): PJSONVariantData; + /// add a void TJSONVariantData to the jvArray and return a pointer to it + function AddItem: PJSONVariantData; + /// add a value to the jvArray + // - raise a ESJONException if the instance is a jvObject + procedure AddValue(const aValue: variant); + /// add a name/value pair to the jvObject + // - raise a ESJONException if the instance is a jvArray + procedure AddNameValue(const aName: string; const aValue: variant); + /// search for a name in this jvObject + function NameIndex(const aName: string): integer; + /// set a value of this jvObject to a given path + // - aPath can be specified with any depth, e.g. 'level1.level2.level3' + procedure SetPath(const aPath: string; const aValue: variant); + /// fill this document from a JSON array or object + function FromJSON(const JSON: string): boolean; + /// convert this document into JSON array or object + function ToJSON: string; + /// fill the published properties of supplied class from this JSON object + function ToObject(Instance: TObject): boolean; + /// create an instance, and fill its published properties from this JSON object + // - it should contain some "ClassName" properties, i.e. JSON should have + // been created by ObjectToJSON(Instance,true) and the class should have + // been registered with RegisterClassForJSON() + function ToNewObject: TObject; + /// kind of document this TJSONVariantData contains + // - returns jvUndefined if this instance is not a TJSONVariant custom variant + property Kind: TJSONVariantKind read GetKind; + /// number of items in this jvObject or jvArray + // - returns 0 if this instance is not a TJSONVariant custom variant + property Count: integer read GetCount; + /// access by name to a value of this jvObject + // - value is returned as (varVariant or varByRef) for best speed + // - will return UnAssigned if aName is not correct or this is not a jvObject + property Value[const aName: string]: variant read GetValue write SetValue; default; + /// access by name to a value of this jvObject + // - value is returned as a true copy (not varByRef) so this property is + // slower but safer than Value[], if the owning TJsonVariantData disappears + // - will return UnAssigned if aName is not correct or this is not a jvObject + property ValueCopy[const aName: string]: variant read GetValueCopy; + /// access by index to a value of this jvArray + // - will return UnAssigned if aIndex is not correct or this is not a jvArray + property Item[aIndex: integer]: variant read GetItem write SetItem; + end; + {$A+} + + /// low-level class used to register TJSONVariantData as custom type + // - allows late binding to values, e.g. + // ! jsonvar.avalue := jsonvar.avalue+1; + // - due to an issue with FPC implementation, you can only read properties, + // not set them, so you should write: + // ! TJSONVariantData(jsonvar)['avalue'] := jsonvar.avalue+1; + TJSONVariant = class(TInvokeableVariantType) + protected + {$ifndef FPC} + {$ifndef ISDELPHI6} + function FixupIdent(const AText: string): string; override; + {$endif} + {$endif} + public + procedure Copy(var Dest: TVarData; const Source: TVarData; + const Indirect: Boolean); override; + procedure Clear(var V: TVarData); override; + function GetProperty(var Dest: TVarData; const V: TVarData; + const Name: string): Boolean; override; + {$ifdef FPC_VARIANTSETVAR} // see http://mantis.freepascal.org/view.php?id=26773 + function SetProperty(var V: TVarData; const Name: string; + const Value: TVarData): Boolean; override; + {$else} + function SetProperty(const V: TVarData; const Name: string; + const Value: TVarData): Boolean; override; + {$endif} + procedure Cast(var Dest: TVarData; const Source: TVarData); override; + procedure CastTo(var Dest: TVarData; const Source: TVarData; + const AVarType: TVarType); override; + end; + + /// handle a JSON result table, as returned by mORMot's server + // - handle both expanded and non expanded layout + // - will be used e.g. on client side for variant-based ORM data parsing + TJSONTable = class + protected + fJSON: string; + fFieldNames: TStringDynArray; + fJSONExpanded: boolean; + fJSONIndexFirstValue: integer; + fJSONCurrentIndex: integer; + fRowValues: TVariantDynArray; + function Get(const FieldName: string): variant; + public + /// parse the supplied JSON content + constructor Create(const aJSON: string); + /// case-insensitive search for a field name + function FieldIndex(const FieldName: string): integer; + /// to be called in a loop to iterate through all data rows + // - if returned true, Value[] contains the fields of this row + function Step(SeekFirst: boolean=false): boolean; + /// to be called in a loop to iterate through all data rows + // - if returned true, RowValues contains this row as TJSONVariant + function StepValue(var RowValues: variant; SeekFirst: boolean=false): boolean; + /// after Step() returned true, can be used to retrieve a field value by name + property Value[const FieldName: string]: variant read Get; default; + /// after Step() returned true, can be used to retrieve a field value by index + property RowValues: TVariantDynArray read fRowValues; + /// the recognized field names + property FieldNames: TStringDynArray read fFieldNames; + /// the associated JSON content + property JSON: string read fJSON; + end; + + /// an abstract type used for RTTI type information + TRTTITypeInfo = PPropInfo; + + /// an abstract type used for RTTI property information + TRTTIPropInfo = PPropInfo; + + TRTTIPropInfoDynArray = array of TRTTIPropInfo; + + /// handle a JSON result table, as returned by mORMot's server + // - handle both expanded and non expanded layout + // - this class is able to use RTTI to fill all published properties of + // a TObject + TJSONTableObject = class(TJSONTable) + protected + fTypeInfo: pointer; + fPropInfo: array of TRTTIPropInfo; + procedure FillPropInfo(aTypeInfo: TRTTITypeInfo); virtual; + procedure FillInstance(Instance: TObject); virtual; + function GetPropInfo(aTypeInfo: TRTTITypeInfo; const PropName: string): TRTTIPropInfo; virtual; + public + /// to be called in a loop to iterate through all data rows + // - if returned true, Object published properties will contain this row + function StepObject(Instance: TObject; SeekFirst: boolean=false): boolean; virtual; + end; + + /// used e.g. by TSynTest for each test case + TPublishedMethod = record + Name: string; + Method: TMethod; + end; + /// as filled by GetPublishedMethods() + TPublishedMethodDynArray = array of TPublishedMethod; + + +/// create a TJSONVariant instance from a given JSON content +// - typical usage may be: +//! var doc: variant; +//! json: string; +//! begin +//! doc := JSONVariant('{"test":1234,"name":"Joh\"n\r"}'); +//! assert(doc.test=1234); // access via late binding +//! assert(doc.name='Joh"n'#13); +//! assert(doc.name2=null); // unknown properties returns null +//! json := doc; // to convert a TJSONVariant to JSON, just assign to a string +//! assert(json='{"test":1234,"name":"Joh\"n\r"}'); +//! end; +// - note that FPC does not allow to set values by late-binding +function JSONVariant(const JSON: string): variant; overload; + +/// create a TJSONVariant TJSONVariant array from a supplied array of values +function JSONVariant(const values: TVariantDynArray): variant; overload; + +/// create a TJSONVariant TJSONVariant array from a supplied array of values +function JSONVariantFromConst(const constValues: array of variant): variant; + +/// access to a TJSONVariant instance members +// - e.g. Kind, Count, Names[] or Values[] +// - will raise an exception if the supplied variant is not a TJSONVariant +// - this function is safer than TJSONVariant(JSONVariant) +function JSONVariantData(const JSONVariant: variant): PJSONVariantData; + +/// access to a TJSONVariant instance members +// - e.g. Kind, Count, Names[] or Values[] +// - will return a read-only fake TJSONVariant with Kind=jvUndefined if the +// supplied variant is not a TJSONVariant +// - if ExpectedKind is jvArray of jvObject, it would return a fake TJSONVariant +// with Kind=jvUndefined if the JSONVariant kind does not match - so you can write: +// !var _a: integer; +// ! _arr: PJSONVariantData; +// !... +// ! _arr := JSONVariantDataSafe(_variant,jvArray); +// ! SetLength(result,_arr.Count); +// ! for _a := 0 to _arr.Count-1 do +// ! result[_a] := _arr.Values[_a]; +// in the above code, _arr.Count will be 0 if _variant.Kind<>jvArray +// - this function is safer than TJSONVariant(JSONVariant) +function JSONVariantDataSafe(const JSONVariant: variant; + ExpectedKind: TJSONVariantKind=jvUndefined): PJSONVariantData; + +var + /// the custom variant type definition registered for TJSONVariant + JSONVariantType: TInvokeableVariantType; + + +/// compute the quoted JSON string corresponding to the supplied text +function StringToJSON(const Text: string): string; + +/// compute the JSON representation of a floating-point value +procedure DoubleToJSON(Value: double; var result: string); + +/// compute the ISO-8601 JSON text representation of a date/time value +// - e.g. "YYYY-MM-DD" "Thh:mm:ss" or "YYYY-MM-DDThh:mm:ss" +// - if Date is 0, will return "" +function DateTimeToJSON(Value: TDateTime): string; + +/// compute the JSON representation of a variant value +// - will work for simple types, or TJSONVariant object or array +function ValueToJSON(const Value: variant): string; + +/// compute a variant from its JSON representation +// - will work for simple types, or TJSONVariant object or array +function JSONToValue(const JSON: string): variant; + +/// compute the ISO-8601 JSON text representation of the current date/time value +// - e.g. "2015-06-27T20:59:29" +function NowToIso8601: string; + +/// compute the unquoted ISO-8601 text representation of a date/time value +// - e.g. 'YYYY-MM-DD' 'Thh:mm:ss' or 'YYYY-MM-DDThh:mm:ss' +// - if Date is 0, will return '' +function DateTimeToIso8601(Value: TDateTime): string; + +/// convert unquoted ISO-8601 text representation into a date/time value +// - e.g. 'YYYY-MM-DD' 'Thh:mm:ss' or 'YYYY-MM-DDThh:mm:ss' +function Iso8601ToDateTime(const Value: string): TDateTime; + +/// compute the JSON representation of an object published properties +// - handle only simple types of properties, not nested class instances +// - any TList/TObjectList/TCollection will be serialized as JSON array +function ObjectToJSON(Instance: TObject; StoreClassName: boolean=false): string; + +/// fill an object published properties from the supplied JSON object +// - handle only simple types of properties, not nested class instances +function JSONToObject(Instance: TObject; const JSON: string): boolean; + +/// create a new object and fil its published properties from the supplied +// JSON object, which should include "ClassName":"..." properties +// - JSON should have been created with ObjectToJSON(Instance,true) and +// the class should have been registered with RegisterClassForJSON() +function JSONToNewObject(const JSON: string): pointer; + +/// register the class types to be created from its name +// - used e.g. by JSONToNewObject() or TJSONVariantData.ToNewObject +procedure RegisterClassForJSON(const Classes: array of TClass); + +/// create a class instance from its name +// - the class should have been registered previously via RegisterClassForJSON() +// - if the supplied class name is not found, will return nil +function CreateClassForJSON(const ClassName: string): TObject; + +/// create a list of object published properties from the supplied JSON object +// - handle only simple types of properties, not nested class instances +function JSONToObjectList(ItemClass: TClass; const JSON: string): TObjectList; + +/// return a string corresponding to the type name, as stored in the RTTI +// - e.g. 'TDateTime', 'TByteDynArray', 'TModTime', 'TCreateTime' +function RTTIPropInfoTypeName(PropInfo: TRTTIPropInfo): string; + +/// retrieve the published properties type information about a given class +procedure GetPropsInfo(TypeInfo: TRTTITypeInfo; var PropNames: TStringDynArray; + var PropRTTI: TRTTIPropInfoDynArray); + +/// retrieve the value of a published property as variant +function GetInstanceProp(Instance: TObject; PropInfo: TRTTIPropInfo): variant; + +/// set the value of a published property from a variant +procedure SetInstanceProp(Instance: TObject; PropInfo: TRTTIPropInfo; + const Value: variant); + +/// retrieve all the published methods of a given class, using RTTI +procedure GetPublishedMethods(Instance: TObject; + out Methods: TPublishedMethodDynArray); + +/// convert an "array of const" parameter value into its string representation +function VarRecToValue(const V: TVarRec; out wasString: boolean): string; + +/// convert the supplied text as "text", as expected by SQL standard +procedure DoubleQuoteStr(var text: string); + +/// decode a Base64-encoded string +// - default withBase64Magic=TRUE will expect the string to start with our +// JSON_BASE64_MAGIC marker +function Base64JSONStringToBytes(const JSONString: string; + var Bytes: TByteDynArray; withBase64Magic: boolean=true): boolean; + +/// Base-64 encode a BLOB into string +// - default withBase64Magic=TRUE will include our JSON_BASE64_MAGIC marker +function BytesToBase64JSONString(const Bytes: TByteDynArray; + withBase64Magic: boolean=true): string; + +const + /// special code to mark Base64 binary content in JSON string + // - Unicode special char U+FFF0 is UTF-8 encoded as EF BF B0 bytes + // - prior to Delphi 2009, it won't work as expected since U+FFF0 won't be + // able to be converted into U+FFF0 + {$ifdef UNICODE} + JSON_BASE64_MAGIC: word = $fff0; + {$else} + JSON_BASE64_MAGIC: array[0..2] of byte = ($ef,$bf,$b0); + {$endif} + + /// size, in platform chars, of our special code to mark Base64 binary + // content in JSON string + // - equals 1 since Delphi 2009 (UTF-16 encoded), or 3 for older versions + // (UTF-8encoded) of the compiler compiler + JSON_BASE64_MAGIC_LEN = sizeof(JSON_BASE64_MAGIC) div sizeof(char); + +{$ifndef ISSMS} +/// read an UTF-8 (JSON) file into a native string +// - file should be existing, otherwise an exception is raised +function UTF8FileToString(const aFileName: TFileName): string; +{$endif} + +/// this function is faster than str := str+chr ! +procedure AppendChar(var str: string; chr: Char); + {$ifdef HASINLINE}inline;{$endif} + +/// check that two ASCII-7 latin text do match +function IdemPropName(const PropName1,PropName2: string): boolean; overload; + {$ifdef HASINLINE}inline;{$endif} + +/// check that two ASCII-7 latin text do match +// - first parameter is expected to be a shortstring low-level buffer - as such, +// this overloaded function would work with NEXTGEN encoded RTTI +function IdemPropName(PropName1: PByteArray; const PropName2: string): boolean; overload; + {$ifdef HASINLINE}inline;{$endif} + +/// convert ASCII-7 latin text, encoded as a shortstring buffer, into a string +// - as such, this function would work with NEXTGEN encoded RTTI +function ShortStringToString(Buffer: PByteArray): string; + +/// check that two ASCII-7 latin text do match +function StartWithPropName(const PropName1,PropName2: string): boolean; + + +implementation + +function IdemPropName(const PropName1,PropName2: string): boolean; +var L,i: integer; +begin + result := false; + L := length(PropName2); + if length(PropName1)<>L then + exit; + for i := 1 to L do + if (ord(PropName1[i]) xor ord(PropName2[i])) and + {$ifdef UNICODE}$ffdf{$else}$df{$endif}<>0 then + exit; + result := true; +end; + +function ShortStringToString(Buffer: PByteArray): string; +{$ifdef UNICODE} +var i: integer; +begin + SetLength(result,Buffer^[0]); + for i := 1 to Buffer^[0] do + result[i] := chr(Buffer^[i]); +end; +{$else} +begin + SetString(result,PAnsiChar(@Buffer^[1]),Buffer^[0]); +end; +{$endif} + +function IdemPropName(PropName1: PByteArray; const PropName2: string): boolean; +var L,i: integer; +begin + result := false; + L := length(PropName2); + if PropName1^[0]<>L then + exit; + for i := 1 to L do + if (PropName1^[i] xor ord(PropName2[i])) and + {$ifdef UNICODE}$ffdf{$else}$df{$endif}<>0 then + exit; + result := true; +end; + +function StartWithPropName(const PropName1,PropName2: string): boolean; +var L,i: integer; +begin + result := false; + L := length(PropName2); + if length(PropName1)0 then + exit; + result := true; +end; + +{$ifndef ISSMS} // there is no file within HTML5 DOM + +{$ifdef FPC} +// assume string is UTF-8 encoded (as with Lazarus/LCL) +// note that when working with variants, FPC 2.7.1 sometimes clear the code page +type UTF8ToString = RawByteString; +{$else} +{$ifndef UNICODE} +function UTF8ToString(const utf8: TUTF8Buffer): string; +begin + result := UTF8ToAnsi(utf8); +end; +{$endif} +{$endif} + +function UTF8FileToString(const aFileName: TFileName): string; +var F: TFileStream; + len: integer; + utf8: TUTF8Buffer; +begin + F := TFileStream.Create(aFileName,fmOpenRead); + try + len := F.Size; + SetLength(utf8,len); + {$ifdef NEXTGEN} + F.Read(utf8[0],len); + result := TEncoding.UTF8.GetString(utf8); + {$else} + F.Read(utf8[1],len); + result := UTF8ToString(utf8); + {$endif} + finally + F.Free; + end; +end; +{$endif} + +function JSONVariant(const JSON: string): variant; +begin + VarClear(result); + TJSONVariantData(result).FromJSON(JSON); +end; + +function JSONVariant(const values: TVariantDynArray): variant; +begin + VarClear(result); + TJSONVariantData(result).Init; + TJSONVariantData(result).VKind := jvArray; + TJSONVariantData(result).VCount := length(values); + TJSONVariantData(result).Values := values; +end; + +function JSONVariantFromConst(const constValues: array of variant): variant; +var i: integer; +begin + VarClear(result); + with TJSONVariantData(result) do begin + Init; + VKind := jvArray; + VCount := length(values); + SetLength(Values,VCount); + for i := 0 to VCount-1 do + Values[i] := constValues[i]; + end; +end; + +function JSONVariantData(const JSONVariant: variant): PJSONVariantData; +begin + with TVarData(JSONVariant) do + if VType=JSONVariantType.VarType then + result := @JSONVariant else + if VType=varByRef or varVariant then + result := JSONVariantData(PVariant(VPointer)^) else + raise EJSONException.CreateFmt('JSONVariantData.Data(%d<>JSONVariant)',[VType]); +end; + +const // will be in code section of the exe, so will be read-only by design + JSONVariantDataFake: TJSONVariantData = (); + +function JSONVariantDataSafe(const JSONVariant: variant; + ExpectedKind: TJSONVariantKind=jvUndefined): PJSONVariantData; +begin + with TVarData(JSONVariant) do + if VType=JSONVariantType.VarType then + if (ExpectedKind=jvUndefined) or + (TJSONVariantData(JSONVariant).VKind=ExpectedKind) then + result := @JSONVariant else + result := @JSONVariantDataFake else + if VType=varByRef or varVariant then + result := JSONVariantDataSafe(PVariant(VPointer)^) else + result := @JSONVariantDataFake; +end; + +procedure AppendChar(var str: string; chr: Char); +{$ifdef ISSMS} // JavaScript immutable strings +begin + str := str+chr +end; +{$else} +var len: Integer; +begin + len := length(str); + SetLength(str,len+1); + PChar(pointer(str))[len] := chr; // SetLength() made str unique +end; +{$endif} + +function StringToJSON(const Text: string): string; +var len,j: integer; +procedure DoEscape; +var i: Integer; +begin + result := '"'+copy(Text,1,j-1); // here FPC 2.7.1 erases UTF-8 encoding + for i := j to len do begin + case Text[i] of + #8: result := result+'\b'; + #9: result := result+'\t'; + #10: result := result+'\n'; + #12: result := result+'\f'; + #13: result := result+'\r'; + '\': result := result+'\\'; + '"': result := result+'\"'; + else + if Text[i]<' ' then + result := result+'\u00'+IntToHex(ord(Text[i]),2) else + AppendChar(result,Text[i]); // will be UTF-8 encoded later + end; + end; + AppendChar(result,'"'); +end; +begin + len := length(Text); + for j := 1 to len do + case Text[j] of + #0..#31,'\','"': begin + DoEscape; + exit; + end; + end; + // if we reached here, no character needs to be escaped in this string + result := '"'+Text+'"'; // here FPC 2.7.1 erases UTF-8 encoding :( +end; + +{$ifdef KYLIX} + {$define NOFORMATSETTINGS} +{$endif} +{$ifdef ISDELPHI6} + {$define NOFORMATSETTINGS} +{$endif} + +{$ifdef NOFORMATSETTINGS} +procedure DoubleToJSON(Value: double; var result: string); +var decsep: Char; +begin // warning: this is NOT thread-safe if you mix settings + decsep := DecimalSeparator; + result := FloatToStr(Value); + DecimalSeparator := decsep; +end; +{$else} +var + SettingsUS: TFormatSettings + {$ifdef FPC} = ( + 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}; +procedure DoubleToJSON(Value: double; var result: string); +begin + result := FloatToStr(Value,SettingsUS); +end; +{$endif} + +function DateTimeToJSON(Value: TDateTime): string; +begin // e.g. "YYYY-MM-DD" "Thh:mm:ss" or "YYYY-MM-DDThh:mm:ss" + result := '"'+DateTimeToIso8601(Value)+'"'; +end; + +function NowToIso8601: string; +begin + result := DateTimeToIso8601(Now); +end; + +function DateTimeToIso8601(Value: TDateTime): string; +begin // e.g. YYYY-MM-DD Thh:mm:ss or YYYY-MM-DDThh:mm:ss + if Value=0 then + result := '' else + if frac(Value)=0 then + result := FormatDateTime('yyyy"-"mm"-"dd',Value) else + if trunc(Value)=0 then + result := FormatDateTime('"T"hh":"nn":"ss',Value) else + result := FormatDateTime('yyyy"-"mm"-"dd"T"hh":"nn":"ss',Value); +end; + +function Iso8601ToDateTime(const Value: string): TDateTime; +var Y,M,D, HH,MI,SS: cardinal; +begin // YYYY-MM-DD Thh:mm:ss or YYYY-MM-DDThh:mm:ss + // 1234567890 123456789 1234567890123456789 + result := 0; + case Length(Value) of + 9: if (Value[1]='T') and (Value[4]=':') and (Value[7]=':') then begin + HH := ord(Value[2])*10+ord(Value[3])-(48+480); + MI := ord(Value[5])*10+ord(Value[6])-(48+480); + SS := ord(Value[8])*10+ord(Value[9])-(48+480); + if (HH<24) and (MI<60) and (SS<60) then + result := EncodeTime(HH,MI,SS,0); + end; + 10: if (Value[5]=Value[8]) and (ord(Value[8]) in [ord('-'),ord('/')]) then begin + Y := ord(Value[1])*1000+ord(Value[2])*100+ + ord(Value[3])*10+ord(Value[4])-(48+480+4800+48000); + M := ord(Value[6])*10+ord(Value[7])-(48+480); + D := ord(Value[9])*10+ord(Value[10])-(48+480); + if (Y<=9999) and ((M-1)<12) and ((D-1)<31) then + result := EncodeDate(Y,M,D); + end; + 19: if (Value[5]=Value[8]) and (ord(Value[8]) in [ord('-'),ord('/')]) and + (ord(Value[11]) in [ord(' '),ord('T')]) and (Value[14]=':') and (Value[17]=':') then begin + Y := ord(Value[1])*1000+ord(Value[2])*100+ + ord(Value[3])*10+ord(Value[4])-(48+480+4800+48000); + M := ord(Value[6])*10+ord(Value[7])-(48+480); + D := ord(Value[9])*10+ord(Value[10])-(48+480); + HH := ord(Value[12])*10+ord(Value[13])-(48+480); + MI := ord(Value[15])*10+ord(Value[16])-(48+480); + SS := ord(Value[18])*10+ord(Value[19])-(48+480); + if (Y<=9999) and ((M-1)<12) and ((D-1)<31) and + (HH<24) and (MI<60) and (SS<60) then + result := EncodeDate(Y,M,D)+EncodeTime(HH,MI,SS,0); + end; + end; +end; + +function ValueToJSON(const Value: variant): string; +var I64: Int64; +begin + if TVarData(Value).VType=JSONVariantType.VarType then + result := TJSONVariantData(Value).ToJSON else + if (TVarData(Value).VType=varByRef or varVariant) then + result := ValueToJSON(PVariant(TVarData(Value).VPointer)^) else + if TVarData(Value).VType<=varNull then + result := 'null' else + if VarIsOrdinal(Value) then begin + I64 := Value; + result := IntToStr(I64); + end else + if TVarData(Value).VType=varDate then + result := DateTimeToJSON(TVarData(Value).VDouble) else + if VarIsFloat(Value) then + DoubleToJSON(Value,result) else + if VarIsStr(Value) then + result := StringToJSON(Value) else + result := Value; +end; + +function VarRecToValue(const V: TVarRec; out wasString: boolean): string; +// http://smartmobilestudio.com/forums/topic/is-array-of-const-supported-in-sms +begin + wasString := not (V.VType in + [vtBoolean,vtInteger,vtInt64,vtCurrency,vtExtended,vtVariant]); + with V do + case VType of + {$ifndef NEXTGEN} + vtString: result := string(VString^); + vtAnsiString: result := string(AnsiString(VAnsiString)); + vtChar: result := string(VChar); + vtPChar: result := string(VPChar); + vtWideString: result := string(WideString(VWideString)); + {$endif} + {$ifdef UNICODE} + vtUnicodeString: result := string(VUnicodeString); + {$endif} + vtPWideChar: result := string(VPWideChar); + vtWideChar: result := string(VWideChar); + vtBoolean: if VBoolean then result := '1' else result := '0'; + vtInteger: result := IntToStr(VInteger); + vtInt64: result := IntToStr(VInt64^); + vtCurrency: DoubleToJSON(VCurrency^,result); + vtExtended: DoubleToJSON(VExtended^,result); + vtObject: result := ObjectToJSON(VObject); + vtVariant: if TVarData(VVariant^).VType<=varNull then + result := 'null' else begin + wasString := VarIsStr(VVariant^); + result := VVariant^; + end; + else result := ''; + end; +end; + +procedure DoubleQuoteStr(var text: string); +var i,j: integer; + tmp: string; +begin + i := pos('"',text); + if i=0 then begin + text := '"'+text+'"'; + exit; + end; + tmp := '"'+copy(text,1,i)+'"'; + for j := i+1 to length(text) do + if text[j]='"' then + tmp := tmp+'""' else + AppendChar(tmp,text[j]); + text := tmp+'"'; +end; + + +{ TJSONParser } + +type + /// the JSON node types, as recognized by TJSONParser + TJSONParserKind = ( + kNone, kNull, kFalse, kTrue, kString, kInteger, kFloat, kObject, kArray); + + /// used to parse any JSON content + TJSONParser = {$ifdef UNICODE}record{$else}object{$endif} + JSON: string; + Index: integer; + JSONLength: integer; + procedure Init(const aJSON: string; aIndex: integer); + function GetNextChar: char; {$ifdef HASINLINE}inline;{$endif} + function GetNextNonWhiteChar: char; {$ifdef HASINLINE}inline;{$endif} + function CheckNextNonWhiteChar(aChar: char): boolean; {$ifdef HASINLINE}inline;{$endif} + function GetNextString(out str: string): boolean; overload; + function GetNextString: string; overload; {$ifdef HASINLINE}inline;{$endif} + function GetNextJSON(out Value: variant): TJSONParserKind; + function CheckNextIdent(const ExpectedIdent: string): Boolean; + function GetNextAlphaPropName(out fieldName: string): boolean; + function ParseJSONObject(var Data: TJSONVariantData): boolean; + function ParseJSONArray(var Data: TJSONVariantData): boolean; + procedure GetNextStringUnEscape(var str: string); + end; + +procedure TJSONParser.Init(const aJSON: string; aIndex: integer); +begin + JSON := aJSON; + JSONLength := length(JSON); + Index := aIndex; +end; + +function TJSONParser.GetNextChar: char; +begin + if Index<=JSONLength then begin + result := JSON[Index]; + inc(Index); + end else + result := #0; +end; + +function TJSONParser.GetNextNonWhiteChar: char; +begin + if Index<=JSONLength then + repeat + if JSON[Index]>' ' then begin + result := JSON[Index]; + inc(Index); + exit; + end; + inc(Index); + until Index>JSONLength; + result := #0; +end; + +function TJSONParser.CheckNextNonWhiteChar(aChar: char): boolean; +begin + if Index<=JSONLength then + repeat + if JSON[Index]>' ' then begin + result := JSON[Index]=aChar; + if result then + inc(Index); + exit; + end; + inc(Index); + until Index>JSONLength; + result := false; +end; + +procedure TJSONParser.GetNextStringUnEscape(var str: string); +var c: char; + u: string; + unicode,err: integer; +begin + repeat + c := GetNextChar; + case c of + #0: exit; + '"': break; + '\': begin + c := GetNextChar; + case c of + #0: exit; + 'b': AppendChar(str,#08); + 't': AppendChar(str,#09); + 'n': AppendChar(str,#$0a); + 'f': AppendChar(str,#$0c); + 'r': AppendChar(str,#$0d); + 'u': begin + u := Copy(JSON,Index,4); + if length(u)<>4 then + exit; + inc(Index,4); + val('$'+u,unicode,err); + if err<>0 then + exit; + AppendChar(str,char(unicode)); + end; + else AppendChar(str,c); + end; + end; + else AppendChar(str,c); + end; + until false; +end; + +function TJSONParser.GetNextString(out str: string): boolean; +var i: integer; +begin + for i := Index to JSONLength do + case JSON[i] of + '"': begin // end of string without escape -> direct copy + str := copy(JSON,Index,i-Index); + Index := i+1; + result := true; + exit; + end; + '\': begin // need unescaping + str := copy(JSON,Index,i-Index); + Index := i; + GetNextStringUnEscape(str); + result := true; + exit; + end; + end; + result := false; +end; + +function TJSONParser.GetNextString: string; +begin + if not GetNextString(result) then + result := ''; +end; + +function TJSONParser.GetNextAlphaPropName(out fieldName: string): boolean; +var i: integer; +begin + result := False; + if (Index>=JSONLength) or + not (Ord(JSON[Index]) in [Ord('A')..Ord('Z'),Ord('a')..Ord('z'),Ord('_'),Ord('$')]) then + exit; // first char must be alphabetical + for i := Index+1 to JSONLength do + case Ord(JSON[i]) of + Ord('0')..Ord('9'),Ord('A')..Ord('Z'),Ord('a')..Ord('z'),Ord('_'): + ; // allow MongoDB extended syntax, e.g. {age:{$gt:18}} + Ord(':'),Ord('='): begin // allow both age:18 and age=18 pairs + fieldName := Copy(JSON,Index,i-Index); + Index := i+1; + result := true; + exit; + end; + else exit; + end; +end; + +function TJSONParser.GetNextJSON(out Value: variant): TJSONParserKind; +var str: string; + i64: Int64; + d: double; + start,err: integer; +begin + result := kNone; + case GetNextNonWhiteChar of + 'n': if copy(JSON,Index,3)='ull' then begin + inc(Index,3); + result := kNull; + Value := null; + end; + 'f': if copy(JSON,Index,4)='alse' then begin + inc(Index,4); + result := kFalse; + Value := false; + end; + 't': if copy(JSON,Index,3)='rue' then begin + inc(Index,3); + result := kTrue; + Value := true; + end; + '"': if GetNextString(str) then begin + result := kString; + Value := str; + end; + '{': if ParseJSONObject(TJSONVariantData(Value)) then + result := kObject; + '[': if ParseJSONArray(TJSONVariantData(Value)) then + result := kArray; + '-','0'..'9': begin + start := Index-1; + while true do + case JSON[Index] of + '-','+','0'..'9','.','E','e': inc(Index); + else break; + end; + str := copy(JSON,start,Index-start); + val(str,i64,err); + if err=0 then begin + Value := i64; + result := kInteger; + end else begin + val(str,d,err); + if err<>0 then + exit; + Value := d; + result := kFloat; + end; + end; + end; +end; + +function TJSONParser.CheckNextIdent(const ExpectedIdent: string): Boolean; +begin + result := (GetNextNonWhiteChar='"') and + (CompareText(GetNextString,ExpectedIdent)=0) and + (GetNextNonWhiteChar=':'); +end; + +function TJSONParser.ParseJSONArray(var Data: TJSONVariantData): boolean; +var item: variant; +begin + result := false; + Data.Init; + if not CheckNextNonWhiteChar(']') then // '[]' -> void array + repeat + if GetNextJSON(item)=kNone then + exit; + Data.AddValue(item); + case GetNextNonWhiteChar of + ',': continue; + ']': break; + else exit; + end; + until false; + SetLength(Data.Values,Data.VCount); + Data.VKind := jvArray; + result := true; +end; + +function TJSONParser.ParseJSONObject(var Data: TJSONVariantData): boolean; +var key: string; + val: variant; +begin + result := false; + Data.Init; + if not CheckNextNonWhiteChar('}') then // '{}' -> void object + repeat + if CheckNextNonWhiteChar('"') then begin + if (not GetNextString(key)) or (GetNextNonWhiteChar<>':') then + exit; + end else + if not GetNextAlphaPropName(key) then + exit; + if GetNextJSON(val)=kNone then + exit; // writeln(Copy(JSON,Index-10,30)); + Data.AddNameValue(key,val); + case GetNextNonWhiteChar of + ',': continue; + '}': break; + else exit; + end; + until false; + SetLength(Data.Names,Data.VCount); + SetLength(Data.Values,Data.VCount); + Data.VKind := jvObject; + result := true; +end; + + +function JSONToValue(const JSON: string): variant; +var Parser: TJSONParser; +begin + Parser.Init(JSON,1); + Parser.GetNextJSON(result); +end; + + +{ RTTI-oriented functions } + +const + BASE64: array[0..63] of char = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +var + BASE64DECODE: array of ShortInt; + +function BytesToBase64JSONString(const Bytes: TByteDynArray; + withBase64Magic: boolean): string; +var i,len,x,c,j: cardinal; + P: PChar; +begin + len := length(Bytes); + if len=0 then begin + result := ''; + exit; + end; + if withBase64Magic then + x := JSON_BASE64_MAGIC_LEN else + x := 0; + SetLength(result,((len+2)div 3)*4+x); + P := pointer(result); + if withBase64Magic then + move(JSON_BASE64_MAGIC,P^,sizeof(JSON_BASE64_MAGIC)); + j := 0; + for i := 1 to len div 3 do begin + c := Bytes[j] shl 16 or Bytes[j+1] shl 8 or Bytes[j+2]; + inc(j,3); + P[x] := BASE64[(c shr 18) and $3f]; + P[x+1] := BASE64[(c shr 12) and $3f]; + P[x+2] := BASE64[(c shr 6) and $3f]; + P[x+3] := BASE64[c and $3f]; + inc(x,4); + end; + case len mod 3 of + 1: begin + c := Bytes[j] shl 4; + P[x] := BASE64[(c shr 6) and $3f]; + P[x+1] := BASE64[c and $3f]; + P[x+2] := '='; + P[x+3] := '='; + inc(x,4); + end; + 2: begin + c := Bytes[j] shl 10 or Bytes[j+1] shl 2; + P[x] := BASE64[(c shr 12) and $3f]; + P[x+1] := BASE64[(c shr 6) and $3f]; + P[x+2] := BASE64[c and $3f]; + P[x+3] := '='; + inc(x,4); + end; + end; + assert(integer(x)=Length(Result)); +end; + +function Base64One(c: Char): integer; + {$ifdef HASINLINE}inline;{$endif} +begin + result := ord(c); + if result>127 then + result := -1 else + result := BASE64DECODE[result]; +end; + +function Base64JSONStringToBytes(const JSONString: string; + var Bytes: TByteDynArray; withBase64Magic: boolean): boolean; +var i,bits,value,x,magiclen,len: cardinal; +begin + result := JSONString=''; + if result then + exit; + if withBase64Magic then + if comparemem(pointer(JSONString),@JSON_BASE64_MAGIC,sizeof(JSON_BASE64_MAGIC)) then + magiclen := JSON_BASE64_MAGIC_LEN else + {$ifndef UNICODE} + if JSONString[1]='?' then // handle UTF-8 decoding error on ANSI Delphi + magiclen := 1 else + {$endif} + exit else + magiclen := 0; // withBase64Magic=false + x := length(JSONString); + len := x-magiclen; + if len and 3<>0 then + exit; + if len=0 then + Bytes := nil else begin + if BASE64DECODE=nil then begin + SetLength(BASE64DECODE,128); + for i := 0 to 127 do + BASE64DECODE[i] := -1; + for i := 0 to high(BASE64) do + BASE64DECODE[ord(BASE64[i])] := i; + end; + len := (len shr 2)*3; + if Base64One(JSONString[x])<0 then begin + dec(len); + if Base64One(JSONString[x-1])<0 then + dec(len); + end; + SetLength(Bytes,len); + bits := 0; + value := 0; + len := 0; + for i := magiclen+1 to Length(JSONString) do begin + x := ord(JSONString[i]); // inlined Base64One(JSONString[i]) + if x>127 then + break; + x := cardinal(BASE64DECODE[x]); + if integer(x)<0 then + break; + value := value*64+x; + bits := bits+6; + if bits>=8 then begin + bits := bits-8; + x := value shr bits; + value := value and ((1 shl bits)-1); + Bytes[len] := x; + inc(len); + end; + end; + end; + result := len=cardinal(length(Bytes)); +end; + +function RTTIPropInfoTypeName(PropInfo: TRTTIPropInfo): string; +begin + result := ShortStringToString(@PropInfo^.PropType^.Name); +end; + +procedure GetPropsInfo(TypeInfo: TRTTITypeInfo; var PropNames: TStringDynArray; + var PropRTTI: TRTTIPropInfoDynArray); +var i,n: integer; + List: PPropList; +begin + n := GetPropList(PTypeInfo(TypeInfo),List); + SetLength(PropNames,n); + SetLength(PropRTTI,n); + for i := 0 to n-1 do begin + PropRTTI[i] := List^[i]; + PropNames[i] := ShortStringToString(@PropRTTI[i]^.Name); + end; + freemem(List); +end; + +function IsDateTime(PropInfo: TRTTIPropInfo): boolean; + {$ifdef HASINLINE}inline;{$endif} +begin + result := PropInfo^.PropType{$ifndef FPC}^{$endif}=TypeInfo(TDateTime); +end; + +type + // used to map a TPropInfo.GetProc/SetProc and retrieve its kind + PropWrap = packed record + FillBytes: array [0..SizeOf(Pointer)-2] of byte; + /// = $ff for a field address, or =$fe for a virtual method + Kind: byte; + end; + +function IsBlob(PropInfo: TRTTIPropInfo): boolean; + {$ifdef HASINLINE}inline;{$endif} +begin // we only handle plain TByteDynArray properties without getter/setter +{$ifdef FPC} + result := (PropInfo^.PropType=TypeInfo(TByteDynArray)) and + (PropInfo^.PropProcs and 3=ptField); +{$else} + result := (PropInfo^.PropType^=TypeInfo(TByteDynArray)) and + (PropWrap(PropInfo^.GetProc).Kind=$FF); +{$endif} +end; + +function GetTByteDynArrayProp(Instance: TObject; PropInfo: TRTTIPropInfo): PByteDynArray; + {$ifdef HASINLINE}inline;{$endif} +begin + result := Pointer(NativeUInt(Instance)+ + (NativeUInt(PropInfo^.GetProc){$ifndef FPC} and $00FFFFFF{$endif})); +end; + +function GetInstanceProp(Instance: TObject; PropInfo: TRTTIPropInfo): variant; +var obj: TObject; +begin + VarClear(result); + if (PropInfo=nil) or (Instance=nil) then + exit; + case PropInfo^.PropType^.Kind of + tkInt64{$ifdef FPC}, tkQWord{$endif}: + result := GetInt64Prop(Instance,PropInfo); + tkEnumeration, tkInteger, tkSet: + result := GetOrdProp(Instance,PropInfo); + {$ifdef NEXTGEN} + tkUString: + result := GetStrProp(Instance,PropInfo); + {$else} + {$ifdef FPC}tkAString,{$endif}tkLString: + result := GetStrProp(Instance,PropInfo); + tkWString: + result := GetWideStrProp(Instance,PropInfo); + {$ifdef UNICODE} + tkUString: + result := GetUnicodeStrProp(Instance,PropInfo); + {$endif UNICODE} + {$endif NEXTGEN} + tkFloat: + if IsDateTime(PropInfo) then + result := DateTimeToIso8601(GetFloatProp(Instance,PropInfo)) else + result := GetFloatProp(Instance,PropInfo); + tkVariant: + result := GetVariantProp(Instance,PropInfo); + tkClass: begin + obj := TObject(NativeInt(GetOrdProp(Instance,PropInfo))); + if obj=nil then + result := null else + TJSONVariantData(result).Init(ObjectToJSON(obj)); + end; + tkDynArray: + if IsBlob(PropInfo) then + result := BytesToBase64JSONString(GetTByteDynArrayProp(Instance,PropInfo)^); + end; +end; + +procedure SetInstanceProp(Instance: TObject; PropInfo: TRTTIPropInfo; + const Value: variant); +var blob: PByteDynArray; + obj: TObject; +begin + if (PropInfo<>nil) and (Instance<>nil) then + case PropInfo^.PropType^.Kind of + tkInt64{$ifdef FPC}, tkQWord{$endif}: + if TVarData(Value).VType=varInt64 then + SetInt64Prop(Instance,PropInfo,TVarData(Value).VInt64) else + SetOrdProp(Instance,PropInfo,Value); + tkEnumeration, tkInteger, tkSet: + SetOrdProp(Instance,PropInfo,Value); + {$ifdef NEXTGEN} + tkUString: + if TVarData(Value).VType<=varNull then + SetStrProp(Instance,PropInfo,'') else + SetStrProp(Instance,PropInfo,Value); + {$else} + {$ifdef FPC}tkAString,{$endif} tkLString: + if TVarData(Value).VType<=varNull then + SetStrProp(Instance,PropInfo,'') else + SetStrProp(Instance,PropInfo,Value); + tkWString: + if TVarData(Value).VType<=varNull then + SetWideStrProp(Instance,PropInfo,'') else + SetWideStrProp(Instance,PropInfo,Value); + {$ifdef UNICODE} + tkUString: + if TVarData(Value).VType<=varNull then + SetUnicodeStrProp(Instance,PropInfo,'') else + SetUnicodeStrProp(Instance,PropInfo,Value); + {$endif UNICODE} + {$endif NEXTGEN} + tkFloat: + if IsDateTime(PropInfo) and VarIsStr(Value) then + SetFloatProp(Instance,PropInfo,Iso8601ToDateTime(Value)) else + SetFloatProp(Instance,PropInfo,Value); + tkVariant: + SetVariantProp(Instance,PropInfo,Value); + tkDynArray: + if IsBlob(PropInfo) then begin + blob := GetTByteDynArrayProp(Instance,PropInfo); + if (TVarData(Value).VType<=varNull) or + not Base64JSONStringToBytes(Value,blob^) then + Finalize(blob^); + end; + tkClass: begin + obj := TObject(NativeInt(GetOrdProp(Instance,PropInfo))); + if TVarData(Value).VType>varNull then + if obj=nil then begin + obj := JSONVariantData(Value)^.ToNewObject; + if obj<>nil then + SetOrdProp(Instance,PropInfo,NativeInt(obj)); + end else + JSONVariantData(Value)^.ToObject(obj); + end; + end; +end; + +function JSONToObjectList(ItemClass: TClass; const JSON: string): TObjectList; +var doc: TJSONVariantData; + item: TObject; + i: integer; +begin + doc.Init(JSON); + if (doc.VKind<>jvArray) or (ItemClass=nil) then + result := nil else begin + result := TObjectList.Create; + for i := 0 to doc.Count-1 do begin + item := ItemClass.Create; + if not JSONVariantData(doc.Values[i])^.ToObject(item) then begin + FreeAndNil(result); + exit; + end; + result.Add(item); + end; + end; +end; + +function JSONToObject(Instance: TObject; const JSON: string): boolean; +var doc: TJSONVariantData; +begin + if Instance=nil then + result := false else begin + doc.Init(JSON); + result := doc.ToObject(Instance); + end; +end; + +function JSONToNewObject(const JSON: string): pointer; +var doc: TJSONVariantData; +begin + doc.Init(JSON); + result := doc.ToNewObject; +end; + +var + RegisteredClass: array of record + ClassName: string; + ClassType: TClass; + end; + +function FindClassForJSON(const ClassName: string): integer; +begin + for result := 0 to high(RegisteredClass) do + if IdemPropName(RegisteredClass[result].ClassName,ClassName) then + exit; + result := -1; +end; + +function CreateClassForJSON(const ClassName: string): TObject; +var i: integer; +begin + i := FindClassForJSON(ClassName); + if i<0 then + result := nil else + result := RegisteredClass[i].ClassType.Create; +end; + +procedure RegisterClassForJSON(const Classes: array of TClass); +var c,i: integer; + name: string; +begin + for c := 0 to high(Classes) do begin + name := string(Classes[c].ClassName); + i := FindClassForJSON(name); + if i>=0 then + continue; + i := length(RegisteredClass); + SetLength(RegisteredClass,i+1); + RegisteredClass[i].ClassName := Name; + RegisteredClass[i].ClassType := Classes[c]; + end; +end; + +function ObjectToJSON(Instance: TObject; StoreClassName: boolean): string; +var TypeInfo: PTypeInfo; + PropCount, i: integer; + PropList: PPropList; + PropInfo: PPropInfo; +begin + if Instance=nil then begin + result := 'null'; + exit; + end; + {$ifndef NEXTGEN} + if Instance.InheritsFrom(TList) then begin + if TList(Instance).Count=0 then + result := '[]' else begin + result := '['; + for i := 0 to TList(Instance).Count-1 do + result := result+ObjectToJSON(TObject( + TList(Instance).List{$ifdef FPC}^{$endif}[i]),StoreClassName)+','; + result[length(result)] := ']'; + end; + exit; + end; + {$endif} + if Instance.InheritsFrom(TStrings) then begin + if TStrings(Instance).Count=0 then + result := '[]' else begin + result := '['; + for i := 0 to TStrings(Instance).Count-1 do + result := result+StringToJSON(TStrings(Instance).Strings[i])+','; + result[length(result)] := ']'; + end; + exit; + end; + if Instance.InheritsFrom(TCollection) then begin + if TCollection(Instance).Count=0 then + result := '[]' else begin + result := '['; + for i := 0 to TCollection(Instance).Count-1 do + result := result+ObjectToJSON(TCollection(Instance).Items[i],StoreClassName)+','; + result[length(result)] := ']'; + end; + exit; + end; + TypeInfo := Instance.ClassInfo; + if TypeInfo=nil then begin + result := 'null'; + exit; + end; + PropCount := GetPropList(TypeInfo,PropList); + if PropCount>0 then + try + if StoreClassName then + result := '{"ClassName":"'+string(Instance.ClassName)+'",' else + result := '{'; + for i := 0 to PropCount-1 do begin + PropInfo := PropList^[i]; + result := result+StringToJSON(ShortStringToString(@PropInfo^.Name))+':'+ + ValueToJSON(GetInstanceProp(Instance,PropInfo))+','; + end; + result[length(result)] := '}'; + finally + FreeMem(PropList); + end else + result := 'null'; +end; + +procedure GetPublishedMethods(Instance: TObject; + out Methods: TPublishedMethodDynArray); +var n: integer; + procedure AddParentsFirst(C: TClass); + type + TMethodInfo = packed record + {$ifdef FPC} + Name: PShortString; + Addr: Pointer; + {$else} + Len: Word; + Addr: Pointer; + Name: Byte; + {$endif} + end; + var M: ^TMethodInfo; + Method: TMethod; + i,MCount: integer; + begin + if C=nil then + exit; + AddParentsFirst(C.ClassParent); // put children methods afterward + M := PPointer(NativeInt(C)+vmtMethodTable)^; + if M=nil then + exit; + Method.Data := Instance; + MCount := {$ifdef FPC}PCardinal{$else}PWord{$endif}(M)^; + inc({$ifdef FPC}PCardinal{$else}PWord{$endif}(M)); + for i := 1 to MCount do begin + Method.Code := M^.Addr; + if n>=length(Methods) then + SetLength(Methods,n+32); + Methods[n].Name := {$ifdef FPC}M^.Name^{$else}ShortStringToString(@M^.Name){$endif}; + Methods[n].Method := Method; + inc(n); + {$ifdef FPC} + inc(M); + {$else} + inc(PByte(M),M^.Len); + {$endif} + end; + end; +begin + if Instance=nil then + exit; + n := 0; + AddParentsFirst(Instance.ClassType); + SetLength(Methods,n); +end; + + +{ TJSONVariantData } + +procedure TJSONVariantData.Init; +begin + VType := JSONVariantType.VarType; + {$ifdef UNICODE} // makes compiler happy + _Align := 0; + {$endif} + VKind := jvUndefined; + VCount := 0; + SetLength(Names, 0); + SetLength(Values, 0); + pointer(Names) := nil; + pointer(Values) := nil; +end; + +procedure TJSONVariantData.Init(const JSON: string); +begin + Init; + FromJSON(JSON); + if VType=varNull then + VKind := jvObject else + if VType<>JSONVariantType.VarType then + Init; // we expect a true JSON array or object here +end; + +procedure TJSONVariantData.InitFrom(const aValues: TVariantDynArray); +begin + Init; + VKind := jvArray; + Values := aValues; +end; + +procedure TJSONVariantData.AddNameValue(const aName: string; + const aValue: variant); +begin + if VKind=jvUndefined then + VKind := jvObject else + if VKind<>jvObject then + raise EJSONException.CreateFmt('AddNameValue(%s) over array',[aName]); + if VCount<=length(Values) then begin + SetLength(Values,VCount+VCount shr 3+32); + SetLength(Names,VCount+VCount shr 3+32); + end; + Values[VCount] := aValue; + Names[VCount] := aName; + inc(VCount); +end; + +procedure TJSONVariantData.AddValue(const aValue: variant); +begin + if VKind=jvUndefined then + VKind := jvArray else + if VKind<>jvArray then + raise EJSONException.Create('AddValue() over object'); + if VCount<=length(Values) then + SetLength(Values,VCount+VCount shr 3+32); + Values[VCount] := aValue; + inc(VCount); +end; + +function TJSONVariantData.FromJSON(const JSON: string): boolean; +var Parser: TJSONParser; +begin + Parser.Init(JSON,1); + result := Parser.GetNextJSON(variant(self)) in [kObject,kArray]; +end; + +function TJSONVariantData.Data(const aName: string): PJSONVariantData; +var i: integer; +begin + i := NameIndex(aName); + if (i<0) or (TVarData(Values[i]).VType<>JSONVariantType.VarType) then + result := nil else + result := @Values[i]; +end; + +function TJSONVariantData.GetKind: TJSONVariantKind; +begin + if (@self=nil) or (VType<>JSONVariantType.VarType) then + result := jvUndefined else + result := VKind; +end; + +function TJSONVariantData.GetCount: integer; +begin + if (@self=nil) or (VType<>JSONVariantType.VarType) then + result := 0 else + result := VCount; +end; + +function TJSONVariantData.GetValue(const aName: string): variant; +begin + VarClear(result); + if (@self<>nil) and (VType=JSONVariantType.VarType) and (VKind=jvObject) then + GetVarData(aName,TVarData(result)); +end; + +function TJSONVariantData.GetValueCopy(const aName: string): variant; +var i: cardinal; +begin + VarClear(result); + if (@self<>nil) and (VType=JSONVariantType.VarType) and (VKind=jvObject) then begin + i := cardinal(NameIndex(aName)); + if inil) and (VType=JSONVariantType.VarType) and (VKind=jvArray) then + if cardinal(aIndex)nil) and (VType=JSONVariantType.VarType) and (VKind=jvArray) then + if cardinal(aIndex)nil) and (VType=JSONVariantType.VarType) and (Names<>nil) then + for result := 0 to VCount-1 do + if Names[result]=aName then + exit; + result := -1; +end; + +procedure TJSONVariantData.SetPath(const aPath: string; const aValue: variant); +var i: integer; +begin + for i := length(aPath) downto 1 do + if aPath[i]='.' then begin + EnsureData(copy(aPath,1,i-1))^.SetValue(copy(aPath,i+1,maxInt),aValue); + exit; + end; + SetValue(aPath,aValue); +end; + +function TJSONVariantData.EnsureData(const aPath: string): PJSONVariantData; +var i: integer; + new: TJSONVariantData; +begin // recursive value set + i := Pos('.',aPath); + if i=0 then begin + i := NameIndex(aPath); + if i<0 then begin // not existing: create new + new.Init; + AddNameValue(aPath,variant(new)); + result := @Values[VCount-1]; + end else begin + if TVarData(Values[i]).VType<>JSONVariantType.VarType then begin + VarClear(Values[i]); + TJSONVariantData(Values[i]).Init; // create as TJSONVariantData + end; + result := @Values[i]; + end; + end else + result := EnsureData(copy(aPath,1,i-1))^.EnsureData(copy(aPath,i+1,maxInt)); +end; + +function TJSONVariantData.AddItem: PJSONVariantData; +var new: TJSONVariantData; +begin + new.Init; + AddValue(variant(new)); + result := @Values[VCount-1]; +end; + +procedure TJSONVariantData.SetValue(const aName: string; + const aValue: variant); +var i: integer; +begin + if @self=nil then + raise EJSONException.Create('Unexpected Value[] access'); + if aName='' then + raise EJSONException.Create('Unexpected Value['''']'); + i := NameIndex(aName); + if i<0 then + AddNameValue(aName,aValue) else + Values[i] := aValue; +end; + +function TJSONVariantData.ToJSON: string; +var i: integer; +begin + case VKind of + jvObject: + if VCount=0 then + result := '{}' else begin + result := '{'; + for i := 0 to VCount-1 do + result := result+StringToJSON(Names[i])+':'+ValueToJSON(Values[i])+','; + result[length(result)] := '}'; + end; + jvArray: + if VCount=0 then + result := '[]' else begin + result := '['; + for i := 0 to VCount-1 do + result := result+ValueToJSON(Values[i])+','; + result[length(result)] := ']'; + end; + else result := 'null'; + end; +end; + +function TJSONVariantData.ToNewObject: TObject; +var ndx,i: Integer; +begin + result := nil; + if (Kind<>jvObject) or (Count=0) then + exit; + ndx := NameIndex('ClassName'); + if ndx<0 then + exit; + result := CreateClassForJSON(Values[ndx]); + if result=nil then + exit; // class name has not been registered + for i := 0 to Count-1 do + if i<>ndx then + SetInstanceProp(result,GetPropInfo(result,Names[i]),Values[i]); +end; + +function TJSONVariantData.ToObject(Instance: TObject): boolean; +var i: integer; + aItem: TCollectionItem; +begin + result := false; + if Instance=nil then + exit; + case Kind of + jvObject: + for i := 0 to Count-1 do + SetInstanceProp(Instance, + GetPropInfo(Instance,Names[i]),Values[i]); + jvArray: + if Instance.InheritsFrom(TCollection) then begin + TCollection(Instance).Clear; + for i := 0 to Count-1 do begin + aItem := TCollection(Instance).Add; + if not JSONVariantData(Values[i])^.ToObject(aItem) then + exit; + end; + end else + if Instance.InheritsFrom(TStrings) then + try + TStrings(Instance).BeginUpdate; + TStrings(Instance).Clear; + for i := 0 to Count-1 do + TStrings(Instance).Add(Values[i]); + finally + TStrings(Instance).EndUpdate; + end else + exit; + else + exit; + end; + result := true; +end; + + +{ TJSONVariant } + +procedure TJSONVariant.Cast(var Dest: TVarData; const Source: TVarData); +begin + CastTo(Dest,Source,VarType); +end; + +procedure TJSONVariant.CastTo(var Dest: TVarData; const Source: TVarData; + const AVarType: TVarType); +begin + if Source.VType<>VarType then + RaiseCastError; + variant(Dest) := TJSONVariantData(Source).ToJSON; +end; + +procedure TJSONVariant.Clear(var V: TVarData); +begin + V.VType := varEmpty; + Finalize(TJSONVariantData(V).Names); + Finalize(TJSONVariantData(V).Values); +end; + +procedure TJSONVariant.Copy(var Dest: TVarData; const Source: TVarData; + const Indirect: Boolean); +begin + if Indirect then + SimplisticCopy(Dest,Source,true) else begin + VarClear(variant(Dest)); + TJSONVariantData(Dest).Init; + TJSONVariantData(Dest) := TJSONVariantData(Source); + end; +end; + +{$ifndef FPC} +{$ifndef ISDELPHI6} +function TJSONVariant.FixupIdent(const AText: string): string; +begin // we expect the names to be case-sensitive + result := AText; +end; +{$endif} +{$endif} + +function TJSONVariant.GetProperty(var Dest: TVarData; const V: TVarData; + const Name: string): Boolean; +begin + if not TJSONVariantData(V).GetVarData(Name,Dest) then + Dest.VType := varNull; + result := true; +end; + +{$ifdef FPC_VARIANTSETVAR} +function TJSONVariant.SetProperty(var V: TVarData; const Name: string; + const Value: TVarData): Boolean; +{$else} +function TJSONVariant.SetProperty(const V: TVarData; const Name: string; + const Value: TVarData): Boolean; +{$endif} +begin + {$ifdef FPC} + {$ifndef FPC_VARIANTSETVAR} + raise EJSONException.Create('Setting TJSONVariant via late-binding does not'+ + ' work with FPC - see http://mantis.freepascal.org/view.php?id=26773 -'+ + ' use latest SVN or JSONVariantDataSafe(jsonvar)^[''prop''] := ... instead'); + {$endif} + {$endif} + TJSONVariantData(V).SetValue(Name,variant(Value)); + result := true; +end; + + +{ TJSONTable } + +constructor TJSONTable.Create(const aJSON: string); +var f,firstValue: integer; + EndOfField: char; + fieldCount, fieldName, dummy: variant; + Parser: TJSONParser; +begin + Parser.Init(aJSON,1); + fJSON := aJSON; + EndOfField := #0; + if (Parser.GetNextNonWhiteChar='{') and + Parser.CheckNextIdent('fieldCount') and + (Parser.GetNextJSON(fieldCount)=kInteger) and + (Parser.GetNextNonWhiteChar=',') and + Parser.CheckNextIdent('values') and + (Parser.GetNextNonWhiteChar='[') then begin + // non expanded format: {"fieldCount":2,"values":["ID","Int",1,0,2,0,3,...] + SetLength(fFieldNames,integer(fieldCount)); + for f := 0 to high(fFieldNames) do begin + if Parser.GetNextJSON(fieldName)<>kString then + exit; + fFieldNames[f] := fieldName; + EndOfField := Parser.GetNextNonWhiteChar; + if EndOfField<>',' then + if (EndOfField<>']') or (f<>High(FieldNames)) then + exit + end; + if EndOfField=',' then + fJSONIndexFirstValue := Parser.Index; + end else begin + // expanded format: [{"ID":1,"Int":0},{"ID":2,"Int":0},{"ID":3,...] + Parser.Index := 1; + if (Parser.GetNextNonWhiteChar='[') and + (Parser.GetNextNonWhiteChar='{') then begin + firstValue := Parser.Index; + f := 0; + repeat + if (Parser.GetNextJSON(fieldName)<>kString) or + (Parser.GetNextNonWhiteChar<>':') then + exit; + if Parser.GetNextJSON(dummy)=kNone then + exit; + SetLength(fFieldNames,f+1); + fFieldNames[f] := fieldName; + inc(f); + EndOfField := Parser.GetNextNonWhiteChar; + if EndOfField<>',' then + if EndOfField='}' then + break else + exit; + until false; + fJSONIndexFirstValue := firstValue; + fJSONExpanded := true; + end; + end; + SetLength(fRowValues,length(fFieldNames)); +end; + +function TJSONTable.FieldIndex(const FieldName: string): integer; +begin + for result := 0 to high(fFieldNames) do + if CompareText(fFieldNames[result],FieldName)=0 then + exit; + result := -1; +end; + +function TJSONTable.Get(const FieldName: string): variant; +var ndx: integer; +begin + ndx := FieldIndex(FieldName); + if ndx<0 then + result := null else + result := fRowValues[ndx]; +end; + +function TJSONTable.Step(SeekFirst: boolean): boolean; +var f: integer; + EndOfField: char; + Parser: TJSONParser; +begin + result := false; + if SeekFirst or (fJSONCurrentIndex=0) then + fJSONCurrentIndex := fJSONIndexFirstValue; + if fJSONCurrentIndex<=0 then + exit; + Parser.Init(fJSON,fJSONCurrentIndex); + fJSONCurrentIndex := -1; // indicates end of content in case of exit below + EndOfField := #0; + for f := 0 to high(fRowValues) do begin + if fJSONExpanded and not Parser.CheckNextIdent(fFieldNames[f]) then + exit; + if Parser.GetNextJSON(fRowValues[f])=kNone then + exit; + EndOfField := Parser.GetNextNonWhiteChar; + if EndOfField<>',' then + if f<>High(fRowValues) then + exit else + if ((EndOfField=']') and (not fJSONExpanded)) or + ((EndOfField='}') and fJSONExpanded) then + break else + exit; + end; + if fJSONExpanded then begin + if EndOfField<>'}' then + exit; + EndOfField := Parser.GetNextNonWhiteChar; + if (EndOfField=',') and + (Parser.GetNextNonWhiteChar<>'{') then + exit; + end; + if EndOfField=',' then + fJSONCurrentIndex := Parser.Index; // indicates next Step() has data + result := true; +end; + +function TJSONTable.StepValue(var RowValues: variant; SeekFirst: boolean): boolean; +begin + result := Step(SeekFirst); + if not result then + exit; + if TVarData(RowValues).VType<>JSONVariantType.VarType then begin + VarClear(RowValues); + TJSONVariantData(RowValues).Init; + end; + TJSONVariantData(RowValues).VKind := jvObject; + TJSONVariantData(RowValues).VCount := Length(fFieldNames); + TJSONVariantData(RowValues).Names := fFieldNames; + TJSONVariantData(RowValues).Values := fRowValues; +end; + + +{ TJSONTableObject } + +function TJSONTableObject.StepObject(Instance: TObject; SeekFirst: boolean=false): boolean; +begin + if (Instance=nil) then + result := false else + result := Step(SeekFirst); + if result then + FillInstance(Instance); +end; + +procedure TJSONTableObject.FillInstance(Instance: TObject); +var i: integer; +begin + if fTypeInfo<>Instance.ClassInfo then + FillPropInfo(Instance.ClassInfo); + for i := 0 to Length(fPropInfo)-1 do + SetInstanceProp(Instance,fPropInfo[i],fRowValues[i]); +end; + +function TJSONTableObject.GetPropInfo(aTypeInfo: TRTTITypeInfo; + const PropName: string): TRTTIPropInfo; +begin + result := TypInfo.GetPropInfo(PTypeInfo(aTypeInfo),PropName); +end; + +procedure TJSONTableObject.FillPropInfo(aTypeInfo: TRTTITypeInfo); +var i: integer; +begin + fTypeInfo := aTypeInfo; + SetLength(fPropInfo,Length(fFieldNames)); + for i := 0 to length(FieldNames)-1 do + fPropInfo[i] := GetPropInfo(aTypeInfo,fFieldNames[i]); +end; + + +initialization + JSONVariantType := TJSONVariant.Create; + {$ifndef FPC} + {$ifndef NOFORMATSETTINGS} + {$ifdef ISDELPHIXE} + SettingsUS := TFormatSettings.Create('en_US'); + {$else} + GetLocaleFormatSettings($0409,SettingsUS); + {$endif} + {$endif} + {$endif} +end. diff --git a/assets/InstructionEditor/screenshot.png b/assets/InstructionEditor/screenshot.png new file mode 100644 index 0000000..6f78ea1 Binary files /dev/null and b/assets/InstructionEditor/screenshot.png differ diff --git a/assets/InstructionEditor/untHelperClasses.pas b/assets/InstructionEditor/untHelperClasses.pas new file mode 100644 index 0000000..1ff8e66 --- /dev/null +++ b/assets/InstructionEditor/untHelperClasses.pas @@ -0,0 +1,278 @@ +unit untHelperClasses; + +interface + +uses + System.Classes, System.Generics.Collections, SynCrossPlatformJSON; + +type + TSizeFormatter = record + public + class function Format(Size: UInt64): String; static; + end; + + TStringHelper = record + public + {** + * Fast alternative to the @c System.StrUtils.IndexStr function + * + * @param S The string to search for. + * @param Values The array of strings to search in. + * + * @return The index of @c S in the @c Values array or -1, if not found. + *} + class function IndexStr(const S: String; const Values: array of String): Integer; static; + {** + * Fast alternative to the @c System.SysUtils.AnsiLowerCase function + * + * @param S A reference to the target string. + *} + class procedure AnsiLowerCase(var S: String); static; + end; + + TJSONHelper = record + public + class function JSONToString(JSON: PJSONVariantData; const Ident: String = ''): String; static; + end; + + TStringBuffer = class(TObject) + strict private + FBuffer: array of Char; + FPosition: Integer; + FCapacity: Integer; + FChunkSize: Integer; + strict private + function GetValue: String; inline; + public + procedure Append(const S: String); + procedure AppendLn(const S: String); + public + constructor Create; + public + property Value: String read GetValue; + property ChunkSize: Integer read FChunkSize write FChunkSize; + end; + +implementation + +uses + System.SysUtils, System.Variants; + +{ TSizeFormatter } + +class function TSizeFormatter.Format(Size: UInt64): String; +const + SZ_KB = 1024; + SZ_MB = 1024 * 1024; + SZ_GB = 1024 * 1024; +var + Format: TFormatSettings; +begin + Format := System.SysUtils.FormatSettings; + Format.DecimalSeparator := '.'; + if (Size >= SZ_GB) then + begin + Result := FormatFloat('0.00 GiB', Size / SZ_GB, Format); + end else if (Size >= SZ_MB) then + begin + Result := FormatFloat('0.00 MiB', Size / SZ_MB, Format); + end else if (Size >= SZ_KB) then + begin + Result := FormatFloat('0.00 KiB', Size / SZ_KB, Format); + end else + begin + Result := FormatFloat('0.00 Byte', Size, Format); + end; +end; + +{ TStringHelper } + +class function TStringHelper.IndexStr(const S: String; const Values: array of String): Integer; +var + L, I, J: Integer; + B: Boolean; +begin + Result := -1; + L := Length(S); + for I := Low(Values) to High(Values) do + begin + if (L <> Length(Values[I])) then Continue; + B := true; + for J := 1 to Length(S) do + begin + if (S[J] <> Values[I][J]) then + begin + B := false; + Continue; + end; + end; + if (B) then + begin + Result := I; + Break; + end; + end; +end; + +class procedure TStringHelper.AnsiLowerCase(var S: String); +const + Lower: array of Char = + ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z']; +var + I: Integer; +begin + for I := 1 to Length(S) do + begin + if (CharInSet(S[I], ['A'..'Z'])) then + begin + S[I] := Lower[Ord(S[I]) - Ord('A')]; + end; + end; +end; + +{ TJSONHelper } + +class function TJSONHelper.JSONToString(JSON: PJSONVariantData; const Ident: String = ''): String; + +// TODO: This helper function needs refactoring + +procedure JSONToString(Buffer: TStringBuffer; JSON: PJSONVariantData; const Ident: String = ''); + +procedure ValueToJSON(Buffer: TStringBuffer; const Value: Variant); +var + I64: Int64; + B: Boolean; + S: String; +begin + if (TVarData(Value).VType = JSONVariantType.VarType) then + begin + JSONToString(Buffer, @TJSONVariantData(Value), Ident + ' '); + end else if (TVarData(Value).VType = varByRef or varVariant) then + begin + ValueToJSON(Buffer, PVariant(TVarData(Value).VPointer)^) + end else if (TVarData(Value).VType <= varNull) then + begin + Buffer.Append('null'); + end else if (TVarData(Value).VType = varBoolean) then + begin + B := Value; + Buffer.Append(LowerCase(BoolToStr(B, true))); + end else if (VarIsOrdinal(Value)) then + begin + I64 := Value; + Buffer.Append(IntToStr(I64)); + end else if (TVarData(Value).VType = varDate) then + begin + Buffer.Append(DateTimeToJSON(TVarData(Value).VDouble)); + end else if (VarIsFloat(Value)) then + begin + DoubleToJSON(Value, S); + Buffer.Append(S); + end else if (VarIsStr(Value)) then + begin + Buffer.Append(StringToJSON(Value)); + end else + begin + Buffer.Append(Value); + end; +end; + +var + I: Integer; +begin + case JSON.Kind of + jvObject: + begin + Buffer.AppendLn('{'); + for I := 0 to JSON.Count - 1 do + begin + Buffer.Append(Ident); + Buffer.Append(' '); + Buffer.Append(StringToJSON(JSON.Names[I]) + ': '); + ValueToJSON(Buffer, JSON.Values[I]); + if (I = JSON.Count - 1) then + begin + Buffer.AppendLn(''); + end else + begin + Buffer.AppendLn(','); + end; + end; + Buffer.Append(Ident); + Buffer.Append('}'); + end; + jvArray: + begin + Buffer.AppendLn('['); + for I := 0 to JSON.Count - 1 do + begin + Buffer.Append(Ident); + Buffer.Append(' '); + ValueToJSON(Buffer, JSON.Values[I]); + if (I = JSON.Count - 1) then + begin + Buffer.AppendLn(''); + end else + begin + Buffer.AppendLn(','); + end; + end; + Buffer.Append(Ident); + Buffer.Append(']'); + end else + begin + Buffer.Append('null'); + end; + end; +end; + +var + Buffer: TStringBuffer; +begin + Buffer := TStringBuffer.Create; + try + JSONToString(Buffer, JSON, Ident); + Result := Buffer.Value; + finally + Buffer.Free; + end; +end; + +{ TStringBuffer } + +procedure TStringBuffer.Append(const S: String); +var + L: Integer; +begin + L := Length(S); + while (FPosition + L > FCapacity) do + begin + Inc(FCapacity, FChunkSize); + SetLength(FBuffer, FCapacity); + end; + Move(S[1], FBuffer[FPosition], L * SizeOf(FBuffer[0])); + Inc(FPosition, L); +end; + +procedure TStringBuffer.AppendLn(const S: String); +begin + Append(S); + Append(sLineBreak); +end; + +constructor TStringBuffer.Create; +begin + inherited Create; + FChunkSize := 1024 * 16; + FCapacity := FChunkSize; + SetLength(FBuffer, FChunkSize); +end; + +function TStringBuffer.GetValue: String; +begin + SetLength(Result, FPosition); + Move(FBuffer[0], Result[1], FPosition * SizeOf(FBuffer[0])); +end; + +end. diff --git a/assets/InstructionEditor/untInstructionEditor.pas b/assets/InstructionEditor/untInstructionEditor.pas new file mode 100644 index 0000000..5c59904 --- /dev/null +++ b/assets/InstructionEditor/untInstructionEditor.pas @@ -0,0 +1,4611 @@ +unit untInstructionEditor; + +interface + +uses + System.Classes, System.Generics.Collections, SynCrossPlatformJSON; + +type + TInstructionEditor = class; + TInstructionDefinition = class; + TDefinitionContainer = class; + + TExtInstructionMode = ( + imNeutral, + imRequire64BitMode, + imExclude64BitMode + ); + + TExtMandatoryPrefix = ( + mpNone, + mpPrefix66, + mpPrefixF3, + mpPrefixF2 + ); + + TExtModrmMod = ( + mdNeutral, + mdMemory, + mdRegister + ); + + TExtModrmReg = ( + rgNeutral, + rg0, + rg1, + rg2, + rg3, + rg4, + rg5, + rg6, + rg7 + ); + + TExtModrmRm = ( + rmNeutral, + rm0, + rm1, + rm2, + rm3, + rm4, + rm5, + rm6, + rm7 + ); + + TExtOperandSize = ( + osNeutral, + os16Bit, + os32Bit + ); + + TExtAddressSize = ( + asNeutral, + as16Bit, + as32Bit, + as64Bit + ); + + TExtBitFilter = ( + bfRexW, + bfVexL, + bfEvexL2, + bfEvexB + ); + + TExtBitFilters = set of TExtBitFilter; + + TOpcodeExtensions = class(TPersistent) + strict private + FDefinition: TInstructionDefinition; + strict private + FMode: TExtInstructionMode; + FMandatoryPrefix: TExtMandatoryPrefix; + FModrmMod: TExtModrmMod; + FModrmReg: TExtModrmReg; + FModrmRm: TExtModrmRm; + FOperandSize: TExtOperandSize; + FAddressSize: TExtAddressSize; + FBitFilters: TExtBitFilters; + strict private + procedure SetMode(const Value: TExtInstructionMode); inline; + procedure SetMandatoryPrefix(const Value: TExtMandatoryPrefix); inline; + procedure SetModrmMod(const Value: TExtModrmMod); inline; + procedure SetModrmReg(const Value: TExtModrmReg); inline; + procedure SetModrmRm(const Value: TExtModrmRm); inline; + procedure SetOperandSize(const Value: TExtOperandSize); inline; + procedure SetAddressSize(const Value: TExtAddressSize); inline; + procedure SetBitFilters(const Value: TExtBitFilters); inline; + private + procedure Changed; inline; + private + procedure LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); + procedure SaveToJSON(JSON: PJSONVariantData; const FieldName: String); + procedure SetPrefix(const Value: TExtMandatoryPrefix); + protected + procedure AssignTo(Dest: TPersistent); override; + protected + constructor Create(Definition: TInstructionDefinition); + public + function Equals(const Value: TOpcodeExtensions): Boolean; reintroduce; + published + property Mode: TExtInstructionMode read FMode write SetMode default imNeutral; + property MandatoryPrefix: TExtMandatoryPrefix read FMandatoryPrefix write + SetMandatoryPrefix default mpNone; + property ModrmMod: TExtModrmMod read FModrmMod write SetModrmMod default mdNeutral; + property ModrmReg: TExtModrmReg read FModrmReg write SetModrmReg default rgNeutral; + property ModrmRm: TExtModrmRm read FModrmRm write SetModrmRm default rmNeutral; + property OperandSize: TExtOperandSize read FOperandSize write SetOperandSize default osNeutral; + property AddressSize: TExtAddressSize read FAddressSize write SetAddressSize default asNeutral; + property BitFilters: TExtBitFilters read FBitFilters write SetBitFilters default []; + end; + + TCPUIDFeatureFlag = ( + cf3DNOW, + cfADX, + cfAESNI, + cfAVX, + cfAVX2, + cfAVX512BW, + cfAVX512CD, + cfAVX512DQ, + cfAVX512ER, + cfAVX512F, + cfAVX512PF, + cfAVX512VL, + cfBMI1, + cfBMI2, + cfCMOV, + cfCMPXCHG16B, + cfF16C, + cfFMA, + cfFMA4, + cfFSGSBASE, + cfHLE, + cfLZCNT, + cfMMX, + cfMOVBE, + cfMPX, + cfPCLMUL, + cfPOPCNT, + cfPREFETCHW, + cfRDRAND, + cfRDSEED, + cfRTM, + cfSHA, + cfSSE1, + cfSSE2, + cfSSE3, + cfSSE41, + cfSSE42, + cfSSE4A, + cfSSSE3, + cfTBM, + cfTSX, + cfXOP, + cfFXSR, + cfLAHFSAHF, + cfXSAVE, + cfXSAVES, + cfXSAVEC, + cfXSAVEOPT, + cfMFENCE, + cfVBMI, + cfIFMA + ); + + TCPUIDFeatureFlagSet = set of TCPUIDFeatureFlag; + + TCPUIDFeatureFlags = class(TPersistent) + strict private + FDefinition: TInstructionDefinition; + FFeatureFlags: TCPUIDFeatureFlagSet; + strict private + procedure SetFeatureFlags(const Value: TCPUIDFeatureFlagSet); inline; + strict private + procedure Changed; inline; + private + procedure LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); + procedure SaveToJSON(JSON: PJSONVariantData; const FieldName: String); + protected + procedure AssignTo(Dest: TPersistent); override; + protected + constructor Create(Definition: TInstructionDefinition); + public + function Equals(const Value: TCPUIDFeatureFlags): Boolean; reintroduce; + public + property FeatureFlags: TCPUIDFeatureFlagSet read FFeatureFlags write SetFeatureFlags; + end; + + TX86Register = ( + regNone, + // General purpose registers 64-bit + regRAX, regRCX, regRDX, regRBX, regRSP, regRBP, regRSI, regRDI, + regR8, regR9, regR10, regR11, regR12, regR13, regR14, regR15, + // General purpose registers 32-bit + regEAX, regECX, regEDX, regEBX, regESP, regEBP, regESI, regEDI, + regR8D, regr9D, regR10D, regR11D, regR12D, regR13D, regR14D, regR15D, + // General purpose registers 16-bit + regAX, regCX, regDX, regBX, regSP, regBP, regSI, regDI, + regR8W, regR9W, regR10W, regR11W, regR12W, regR13W, regR14W, regR15W, + // General purpose registers 8-bit + regAL, regCL, regDL, regBL, regAH, regCH, regDH, regBH, + regSPL, regBPL, regSIL, regDIL, + regR8B, regR9B, regR10B, regR11B, regR12B, regR13B, regR14B, regR15B, + // Floating point legacy registers + regST0, regST1, regST2, regST3, regST4, regST5, regST6, regST7, + // Floating point multimedia registers + regMM0, regMM1, regMM2, regMM3, regMM4, regMM5, regMM6, regMM7, + // Floating point vector registers 512-bit + regZMM0, regZMM1, regZMM2, regZMM3, regZMM4, regZMM5, regZMM6, regZMM7, + regZMM8, regZMM9, regZMM10, regZMM11, regZMM12, regZMM13, regZMM14, regZMM15, + regZMM16, regZMM17, regZMM18, regZMM19, regZMM20, regZMM21, regZMM22, regZMM23, + regZMM24, regZMM25, regZMM26, regZMM27, regZMM28, regZMM29, regZMM30, regZMM31, + // Floating point vector registers 256-bit + regYMM0, regYMM1, regYMM2, regYMM3, regYMM4, regYMM5, regYMM6, regYMM7, + regYMM8, regYMM9, regYMM10, regYMM11, regYMM12, regYMM13, regYMM14, regYMM15, + regYMM16, regYMM17, regYMM18, regYMM19, regYMM20, regYMM21, regYMM22, regYMM23, + regYMM24, regYMM25, regYMM26, regYMM27, regYMM28, regYMM29, regYMM30, regYMM31, + // Floating point vector registers 128-bit + regXMM0, regXMM1, regXMM2, regXMM3, regXMM4, regXMM5, regXMM6, regXMM7, + regXMM8, regXMM9, regXMM10, regXMM11, regXMM12, regXMM13, regXMM14, regXMM15, + regXMM16, regXMM17, regXMM18, regXMM19, regXMM20, regXMM21, regXMM22, regXMM23, + regXMM24, regXMM25, regXMM26, regXMM27, regXMM28, regXMM29, regXMM30, regXMM31, + // Special registers + regRFLAGS, regEFLAGS, regFLAGS, regRIP, regEIP, regIP, + // Segment registers + regES, regCS, regSS, regDS, regGS, regFS, + // Control registers + regCR0, regCR1, regCR2, regCR3, regCR4, regCR5, regCR6, regCR7, + regCR8, regCR9, regCR10, regCR11, regCR12, regCR13, regCR14, regCR15, + // Debug registers + regDR0, regDR1, regDR2, regDR3, regDR4, regDR5, regDR6, regDR7, + regDR8, regDR9, regDR10, regDR11, regDR12, regDR13, regDR14, regDR15, + // Mask registers + regK0, regK1, regK2, regK3, regK4, regK5, regK6, regK7, + // Bounds registers + regBND0, regBND1, regBND2, regBND3 + ); + + TX86RegisterSet = set of TX86Register; + + TX86Registers = class(TPersistent) + strict private + FDefinition: TInstructionDefinition; + FRegisters: TX86RegisterSet; + strict private + procedure SetRegisters(const Value: TX86RegisterSet); inline; + strict private + procedure Changed; inline; + private + procedure LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); + procedure SaveToJSON(JSON: PJSONVariantData; const FieldName: String); + protected + procedure AssignTo(Dest: TPersistent); override; + protected + constructor Create(Definition: TInstructionDefinition); + public + function Equals(const Value: TX86Registers): Boolean; reintroduce; + public + property Registers: TX86RegisterSet read FRegisters write SetRegisters; + end; + + TX86FlagValue = ( + fvUnused, + fvTested, + fvModified, + fvReset, + fvSet, + fvUndefined, + fvPriorValue + ); + + TX86Flags = class(TPersistent) + strict private + FDefinition: TInstructionDefinition; + strict private + FCF: TX86FlagValue; + FPF: TX86FlagValue; + FAF: TX86FlagValue; + FZF: TX86FlagValue; + FSF: TX86FlagValue; + FTF: TX86FlagValue; + FIF: TX86FlagValue; + FDF: TX86FlagValue; + FOF: TX86FlagValue; + FRF: TX86FlagValue; + FVM: TX86FlagValue; + FAC: TX86FlagValue; + FVIF: TX86FlagValue; + FVIP: TX86FlagValue; + FID: TX86FlagValue; + strict private + procedure SetCF(const Value: TX86FlagValue); inline; + procedure SetPF(const Value: TX86FlagValue); inline; + procedure SetAF(const Value: TX86FlagValue); inline; + procedure SetZF(const Value: TX86FlagValue); inline; + procedure SetSF(const Value: TX86FlagValue); inline; + procedure SetTF(const Value: TX86FlagValue); inline; + procedure SetIF(const Value: TX86FlagValue); inline; + procedure SetDF(const Value: TX86FlagValue); inline; + procedure SetOF(const Value: TX86FlagValue); inline; + procedure SetRF(const Value: TX86FlagValue); inline; + procedure SetVM(const Value: TX86FlagValue); inline; + procedure SetAC(const Value: TX86FlagValue); inline; + procedure SetVIF(const Value: TX86FlagValue); inline; + procedure SetVIP(const Value: TX86FlagValue); inline; + procedure SetID(const Value: TX86FlagValue); inline; + strict private + procedure Changed; inline; + private + procedure LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); + procedure SaveToJSON(JSON: PJSONVariantData; const FieldName: String); + protected + procedure AssignTo(Dest: TPersistent); override; + protected + constructor Create(Definition: TInstructionDefinition); + public + function Equals(const Value: TX86Flags): Boolean; reintroduce; + published + { FLAGS } + property FlagCF: TX86FlagValue read FCF write SetCF default fvUnused; + property FlagPF: TX86FlagValue read FPF write SetPF default fvUnused; + property FlagAF: TX86FlagValue read FAF write SetAF default fvUnused; + property FlagZF: TX86FlagValue read FZF write SetZF default fvUnused; + property FlagSF: TX86FlagValue read FSF write SetSF default fvUnused; + property FlagTF: TX86FlagValue read FTF write SetTF default fvUnused; + property FlagIF: TX86FlagValue read FIF write SetIF default fvUnused; + property FlagDF: TX86FlagValue read FDF write SetDF default fvUnused; + property FlagOF: TX86FlagValue read FOF write SetOF default fvUnused; + { EFLAGS } + property FlagRF: TX86FlagValue read FRF write SetRF default fvUnused; + property FlagVM: TX86FlagValue read FVM write SetVM default fvUnused; + property FlagAC: TX86FlagValue read FAC write SetAC default fvUnused; + property FlagVIF: TX86FlagValue read FVIF write SetVIF default fvUnused; + property FlagVIP: TX86FlagValue read FVIP write SetVIP default fvUnused; + property FlagID: TX86FlagValue read FID write SetID default fvUnused; + end; + + TInstructionOperands = class; + + TOperandType = ( + optUnused, + optGPR8, + optGPR16, + optGPR32, + optGPR64, + optFPR, + optVR64, + optVR128, + optVR256, + optVR512, + optCR, + optDR, + optSREG, + optMSKR, + optBNDR, + optMem, + optMem8, + optMem16, + optMem32, + optMem64, + optMem80, + optMem128, + optMem256, + optMem512, + optMem32Bcst2, + optMem32Bcst4, + optMem32Bcst8, + optMem32Bcst16, + optMem64Bcst2, + optMem64Bcst4, + optMem64Bcst8, + optMem64Bcst16, + optMem32VSIBX, + optMem32VSIBY, + optMem32VSIBZ, + optMem64VSIBX, + optMem64VSIBY, + optMem64VSIBZ, + optMem1616, + optMem1632, + optMem1664, + optMem112, + optMem224, + optImm8, + optImm8U, + optImm16, + optImm32, + optImm64, + optRel8, + optRel16, + optRel32, + optRel64, + optPtr1616, + optPtr1632, + optPtr1664, + optMoffs16, + optMoffs32, + optMoffs64, + optSrcIndex8, + optSrcIndex16, + optSrcIndex32, + optSrcIndex64, + optDstIndex8, + optDstIndex16, + optDstIndex32, + optDstIndex64, + optFixed1, + optFixedAL, + optFixedCL, + optFixedAX, + optFixedDX, + optFixedEAX, + optFixedRAX, + optFixedST0, + optFixedES, + optFixedSS, + optFixedCS, + optFixedDS, + optFixedFS, + optFixedGS + ); + + TOperandEncoding = ( + opeNone, + opeModrmReg, + opeModrmRm, + opeModrmRmCD1, + opeModrmRmCD2, + opeModrmRmCD4, + opeModrmRmCD8, + opeModrmRmCD16, + opeModrmRmCD32, + opeModrmRmCD64, + opeOpcodeBits, + opeVexVVVV, + opeEvexAAA, + opeImm8, + opeImm16, + opeImm32, + opeImm64 + ); + + TOperandAccessMode = ( + opaRead, + opaWrite, + opaReadWrite + ); + + TInstructionOperand = class(TPersistent) + strict private + FOperands: TInstructionOperands; + FType: TOperandType; + FEncoding: TOperandEncoding; + FAccessMode: TOperandAccessMode; + strict private + function GetConflictState: Boolean; + procedure SetType(const Value: TOperandType); inline; + procedure SetEncoding(const Value: TOperandEncoding); inline; + procedure SetAccessMode(const Value: TOperandAccessMode); inline; + strict private + procedure Changed; inline; + private + procedure LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); + procedure SaveToJSON(JSON: PJSONVariantData; const FieldName: String); + protected + procedure AssignTo(Dest: TPersistent); override; + protected + constructor Create(Operands: TInstructionOperands); + public + function Equals(const Value: TInstructionOperand): Boolean; reintroduce; + public + function GetDescription(IncludeAccessMode: Boolean = true): String; + public + property HasConflicts: Boolean read GetConflictState; + published + property OperandType: TOperandType read FType write SetType default optUnused; + property Encoding: TOperandEncoding read FEncoding write SetEncoding default opeNone; + property AccessMode: TOperandAccessMode read FAccessMode write SetAccessMode default opaRead; + end; + + TInstructionOperands = class(TPersistent) + strict private + FDefinition: TInstructionDefinition; + FOperandA: TInstructionOperand; + FOperandB: TInstructionOperand; + FOperandC: TInstructionOperand; + FOperandD: TInstructionOperand; + strict private + function GetConflictState: Boolean; + private + procedure Changed; inline; + private + function GetOperandById(Id: Integer): TInstructionOperand; inline; + private + procedure LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); + procedure SaveToJSON(JSON: PJSONVariantData; const FieldName: String); + protected + procedure AssignTo(Dest: TPersistent); override; + protected + constructor Create(Definition: TInstructionDefinition); + public + function Equals(const Value: TInstructionOperands): Boolean; reintroduce; + public + destructor Destroy; override; + public + property HasConflicts: Boolean read GetConflictState; + published + property OperandA: TInstructionOperand read FOperandA; + property OperandB: TInstructionOperand read FOperandB; + property OperandC: TInstructionOperand read FOperandC; + property OperandD: TInstructionOperand read FOperandD; + end; + + TInstructionDefinitionConflict = ( + // This conflict is enforced by the user + idcForcedConflict, + // The instruction-operands configuration is invalid + idcOperands + ); + TInstructionDefinitionConflicts = set of TInstructionDefinitionConflict; + + TInstructionEncoding = ( + ieDefault, + ie3DNow, + ieXOP, + ieVEX, + ieEVEX + ); + + TOpcodeMap = ( + omDefault, + om0F, + om0F38, + om0F3A, + omXOP8, + omXOP9, + omXOPA + ); + + TOpcodeByte = type Byte; + + TInstructionDefinitionFlag = ( + ifForceConflict, + ifAcceptsLock, + ifAcceptsREP, + ifAcceptsXACQUIRE, + ifAcceptsXRELEASE, + ifAcceptsEVEXAAA, + ifAcceptsEVEXZ, + ifHasEVEXBC, + ifHasEVEXRC, + ifHasEVEXSAE + ); + TInstructionDefinitionFlags = set of TInstructionDefinitionFlag; + + TInstructionDefinition = class(TPersistent) + strict private + FEditor: TInstructionEditor; + FParent: TDefinitionContainer; + FConflicts: TInstructionDefinitionConflicts; + FData: Pointer; + FUpdateCount: Integer; + FDoUpdatePosition: Boolean; + FDoUpdateValues: Boolean; + strict private + FMnemonic: String; + FEncoding: TInstructionEncoding; + FOpcodeMap: TOpcodeMap; + FOpcode: TOpcodeByte; + FExtensions: TOpcodeExtensions; + FCPUID: TCPUIDFeatureFlags; + FOperands: TInstructionOperands; + FFlags: TInstructionDefinitionFlags; + FImplicitRead: TX86Registers; + FImplicitWrite: TX86Registers; + FX86Flags: TX86Flags; + FEVEXCD8Scale: Cardinal; + FComment: String; + strict private + function GetConflictState: Boolean; inline; + procedure SetMnemonic(const Value: String); inline; + procedure SetEncoding(const Value: TInstructionEncoding); inline; + procedure SetOpcodeMap(const Value: TOpcodeMap); inline; + procedure SetOpcode(const Value: TOpcodeByte); inline; + procedure SetFlags(const Value: TInstructionDefinitionFlags); inline; + procedure SetComment(const Value: String); inline; + strict private + procedure UpdateConflictFlags; + private + procedure UpdatePosition; inline; + procedure UpdateValues; inline; + procedure SetParent(Parent: TDefinitionContainer); inline; + protected + procedure AssignTo(Dest: TPersistent); override; + public + procedure BeginUpdate; inline; + procedure Update; inline; + procedure EndUpdate; inline; + public + function Equals(const Value: TInstructionDefinition): Boolean; reintroduce; + public + procedure LoadFromJSON(JSON: PJSONVariantData); + procedure SaveToJSON(JSON: PJSONVariantData); + public + constructor Create(Editor: TInstructionEditor; const Mnemonic: String); + destructor Destroy; override; + public + property Editor: TInstructionEditor read FEditor; + property Parent: TDefinitionContainer read FParent; + property HasConflicts: Boolean read GetConflictState; + property Data: Pointer read FData write FData; + published + property Mnemonic: String read FMnemonic write SetMnemonic; + property Encoding: TInstructionEncoding read FEncoding write SetEncoding default ieDefault; + property OpcodeMap: TOpcodeMap read FOpcodeMap write SetOpcodeMap default omDefault; + property Opcode: TOpcodeByte read FOpcode write SetOpcode; + property OpcodeExtensions: TOpcodeExtensions read FExtensions; + property CPUID: TCPUIDFeatureFlags read FCPUID; + property Operands: TInstructionOperands read FOperands; + property Flags: TInstructionDefinitionFlags read FFlags write SetFlags; + property ImplicitRead: TX86Registers read FImplicitRead; + property ImplicitWrite: TX86Registers read FImplicitWrite; + property X86Flags: TX86Flags read FX86Flags; + property EVEXCD8Scale: Cardinal read FEVEXCD8Scale default 0; + property Comment: String read FComment write SetComment; + property Conflicts: TInstructionDefinitionConflicts read FConflicts; + end; + + TInstructionFilterFlag = ( + // This is the root table + iffIsRootTable, + // This is a static filter that should not be removed. + // Warning: Never create static tables as child of non-static ones. The code assumes that the + // parent of a static-table is always another static table. + iffIsStaticFilter, + // This is a definition container and not an actual filter + iffIsDefinitionContainer + ); + TInstructionFilterFlags = set of TInstructionFilterFlag; + + TNeutralElementType = ( + // The neutral "zero" element is not supported + netNotAvailable, + // The neutral "zero" element is supported and used as a placeholder. The filter will signal a + // conflict, if the neutral element AND at least one regular value is set. + netPlaceholder, + // The neutral "zero" element is supported and can be used as a regular value + netValue + ); + + TInstructionFilterConflict = ( + // This filter is affected by a conflict of one or more child-filters + ifcInheritedConflict, + // This definition-container holds more than one instruction definition + ifcDefinitionCount, + // The neutral element and at least one regular value is set + ifcNeutralElement + ); + TInstructionFilterConflicts = set of TInstructionFilterConflict; + + TInstructionFilterClass = class of TInstructionFilter; + + PInstructionFilterList = ^TInstructionFilterList; + TInstructionFilterList = array of TInstructionFilterClass; + + TInstructionFilter = class(TPersistent) + strict private + FEditor: TInstructionEditor; + FParent: TInstructionFilter; + FItems: TArray; + FDefinitions: TList; + FConflicts: TInstructionFilterConflicts; + FInheritedConflicts: Integer; + FItemCount: Integer; + FData: Pointer; + strict private + FFilterFlags: TInstructionFilterFlags; + strict private + function GetItem(const Index: Integer): TInstructionFilter; inline; + function GetDefinition(const Index: Integer): TInstructionDefinition; inline; + function GetDefinitionCount: Integer; inline; + function GetConflictState: Boolean; inline; + procedure SetParent(Parent: TInstructionFilter); inline; + procedure SetConflicts(const Value: TInstructionFilterConflicts); inline; + strict private + procedure Changed; inline; + private + procedure SetItem(const Index: Integer; const Value: TInstructionFilter); inline; + private + procedure IncInheritedConflictCount; inline; + procedure DecInheritedConflictCount; inline; + private + procedure CreateFilterAtIndex(Index: Integer; FilterClass: TInstructionFilterClass; + IsRootTable, IsStaticFilter: Boolean); + procedure InsertDefinition(Definition: TInstructionDefinition); + procedure RemoveDefinition(Definition: TInstructionDefinition); + protected + constructor Create(Editor: TInstructionEditor; Parent: TInstructionFilter; + IsRootTable, IsStaticFilter: Boolean); virtual; + protected + property Definitions[const Index: Integer]: TInstructionDefinition read GetDefinition; + property DefinitionCount: Integer read GetDefinitionCount; + public + class function IsDefinitionContainer: Boolean; virtual; + class function GetNeutralElementType: TNeutralElementType; virtual; + class function GetCapacity: Cardinal; virtual; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; virtual; + class function GetDescription: String; virtual; + class function GetItemDescription(Index: Integer): String; virtual; + public + function IndexOf(const Filter: TInstructionFilter): Integer; + public + destructor Destroy; override; + public + property Editor: TInstructionEditor read FEditor; + property Parent: TInstructionFilter read FParent; + property Items[const Index: Integer]: TInstructionFilter read GetItem; + property HasConflicts: Boolean read GetConflictState; + property Data: Pointer read FData write FData; + published + property FilterFlags: TInstructionFilterFlags read FFilterFlags; + property NeutralElementType: TNeutralElementType read GetNeutralElementType; + property Capacity: Cardinal read GetCapacity; + property Conflicts: TInstructionFilterConflicts read FConflicts; + property ItemCount: Integer read FItemCount; + end; + + TDefinitionContainer = class(TInstructionFilter) + public + class function IsDefinitionContainer: Boolean; override; + public + property Definitions; + published + property DefinitionCount; + end; + + TEditorWorkStartEvent = + procedure(Sender: TObject; MinWorkCount, MaxWorkCount: Integer) of Object; + TEditorWorkEvent = + procedure(Sender: TObject; WorkCount: Integer) of Object; + TEditorFilterEvent = + procedure(Sender: TObject; Filter: TInstructionFilter) of Object; + TEditorDefinitionEvent = + procedure(Sender: TObject; Definition: TInstructionDefinition) of Object; + + TInstructionEditor = class(TObject) + strict private + class var FilterOrderDef: TInstructionFilterList; + class var FilterOrderXOP: TInstructionFilterList; + class var FilterOrderVEX: TInstructionFilterList; + class var FilterOrderEVEX: TInstructionFilterList; + strict private + class function GetFilterList(Encoding: TInstructionEncoding): PInstructionFilterList; inline; + strict private + FDefinitions: TList; + FRootTable: TInstructionFilter; + FFilterCount: Integer; + FUpdateCount: Integer; + FPreventDefinitionRemoval: Boolean; + strict private + FOnWorkStart: TEditorWorkStartEvent; + FOnWork: TEditorWorkEvent; + FOnWorkEnd: TNotifyEvent; + FOnBeginUpdate: TNotifyEvent; + FOnEndUpdate: TNotifyEvent; + FOnFilterCreated: TEditorFilterEvent; + FOnFilterInserted: TEditorFilterEvent; + FOnFilterChanged: TEditorFilterEvent; + FOnFilterRemoved: TEditorFilterEvent; + FOnFilterDestroyed: TEditorFilterEvent; + FOnDefinitionCreated: TEditorDefinitionEvent; + FOnDefinitionInserted: TEditorDefinitionEvent; + FOnDefinitionChanged: TEditorDefinitionEvent; + FOnDefinitionRemoved: TEditorDefinitionEvent; + FOnDefinitionDestroyed: TEditorDefinitionEvent; + strict private + function GetDefinition(const Index: Integer): TInstructionDefinition; inline; + function GetDefinitionCount: Integer; inline; + strict private + function GetDefinitionTopLevelFilter(Definition: TInstructionDefinition): TInstructionFilter; + private + procedure RegisterDefinition(Definition: TInstructionDefinition); inline; + procedure InsertDefinition(Definition: TInstructionDefinition); + procedure RemoveDefinition(Definition: TInstructionDefinition); inline; + procedure UnregisterDefinition(Definition: TInstructionDefinition); inline; + private + procedure FilterCreated(Filter: TInstructionFilter); inline; + procedure FilterInserted(Filter: TInstructionFilter); inline; + procedure FilterChanged(Filter: TInstructionFilter); inline; + procedure FilterRemoved(Filter: TInstructionFilter); inline; + procedure FilterDestroyed(Filter: TInstructionFilter); inline; + procedure DefinitionInserted(Definition: TInstructionDefinition); inline; + procedure DefinitionChanged(Definition: TInstructionDefinition); inline; + procedure DefinitionRemoved(Definition: TInstructionDefinition); inline; + public + class constructor Create; + public + procedure BeginUpdate; inline; + procedure EndUpdate; inline; + public + procedure LoadFromJSON(JSON: PJSONVariantData); + procedure SaveToJSON(JSON: PJSONVariantData); + procedure LoadFromFile(const Filename: String); + procedure SaveToFile(const Filename: String); + procedure Reset; + public + function CreateDefinition(const Mnemonic: String): TInstructionDefinition; inline; + public + constructor Create; + destructor Destroy; override; + public + property RootTable: TInstructionFilter read FRootTable; + property FilterCount: Integer read FFilterCount; + property Definitions[const Index: Integer]: TInstructionDefinition read GetDefinition; + property DefinitionCount: Integer read GetDefinitionCount; + public + property OnWorkStart: TEditorWorkStartEvent read FOnWorkStart write FOnWorkStart; + property OnWork: TEditorWorkEvent read FOnWork write FOnWork; + property OnWorkEnd: TNotifyEvent read FOnWorkEnd write FOnWorkEnd; + property OnBeginUpdate: TNotifyEvent read FOnBeginUpdate write FOnBeginUpdate; + property OnEndUpdate: TNotifyEvent read FOnEndUpdate write FOnEndUpdate; + property OnFilterCreated: TEditorFilterEvent read FOnFilterCreated write FOnFilterCreated; + property OnFilterInserted: TEditorFilterEvent read FOnFilterInserted write FOnFilterInserted; + property OnFilterChanged: TEditorFilterEvent read FOnFilterChanged write FOnFilterChanged; + property OnFilterRemoved: TEditorFilterEvent read FOnFilterRemoved write FOnFilterRemoved; + property OnFilterDestroyed: TEditorFilterEvent read FOnFilterDestroyed write FOnFilterDestroyed; + property OnDefinitionCreated: TEditorDefinitionEvent read FOnDefinitionCreated write + FOnDefinitionCreated; + property OnDefinitionInserted: TEditorDefinitionEvent read FOnDefinitionInserted write + FOnDefinitionInserted; + property OnDefinitionChanged: TEditorDefinitionEvent read FOnDefinitionChanged write + FOnDefinitionChanged; + property OnDefinitionRemoved: TEditorDefinitionEvent read FOnDefinitionRemoved write + FOnDefinitionRemoved; + property OnDefinitionDestroyed: TEditorDefinitionEvent read FOnDefinitionDestroyed write + FOnDefinitionDestroyed; + end; + + TTableGeneratorStatistics = record + public + FilterCount: Integer; + FilterSize: Cardinal; + DefinitionCount: Integer; + DefinitionSize: Cardinal; + MnemonicCount: Integer; + MnemonicSize: Cardinal; + end; + + TGeneratorWorkOperation = ( + woIndexingDefinitions, + woIndexingFilters, + woGeneratingFilterFiles, + woGeneratingDefinitionFiles, + woGeneratingMnemonicFiles + ); + + TGeneratorWorkStartEvent = + procedure(Sender: TObject; Operation: TGeneratorWorkOperation; MinWorkCount, + MaxWorkCount: Integer) of Object; + TGeneratorWorkEvent = + procedure(Sender: TObject; WorkCount: Integer) of Object; + + TTableGenerator = class(TObject) + strict private type + TIndexedFilterItem = record + public + Id: Integer; + Filter: TInstructionFilter; + Items: array of TIndexedFilterItem; + IsRedirect: Boolean; + end; + TIndexedDefinitionItem = record + public + Id: Integer; + Definition: TInstructionDefinition; + end; + strict private type + PIndexedFilterList = ^TIndexedFilterList; + TIndexedFilterList = TArray>>; + PIndexedDefinitionList = ^TIndexedDefinitionList; + TIndexedDefinitionList = TArray; + PMnemonicList = ^TMnemonicList; + TMnemonicList = TArray; + strict private + FStatistics: TTableGeneratorStatistics; + strict private + FOnWorkStart: TGeneratorWorkStartEvent; + FOnWork: TGeneratorWorkEvent; + FOnWorkEnd: TNotifyEvent; + strict private + procedure WorkStart(Operation: TGeneratorWorkOperation; MinWorkCount: Integer; + MaxWorkCount: Integer); inline; + procedure Work(WorkCount: Integer); inline; + procedure WorkEnd; inline; + strict private + procedure CreateEntityLists(Editor: TInstructionEditor; + var FilterList: TIndexedFilterList; + var DefinitionList: TIndexedDefinitionList; + var MnemonicList: TMnemonicList); + strict private + procedure GenerateInstructionTable(const OutputDirectory: String; + const FilterList: PIndexedFilterList; FilterCount: Integer); + procedure GenerateDefinitionList(const OutputDirectory: String; + const DefinitionList: PIndexedDefinitionList); + procedure GenerateMnemonicLists(const OutputDirectory: String; + const MnemonicList: PMnemonicList); + public + procedure GenerateFiles(Editor: TInstructionEditor; const OutputDirectory: String); + public + constructor Create; + destructor Destroy; override; + public + property Statistics: TTableGeneratorStatistics read FStatistics; + public + property OnWorkStart: TGeneratorWorkStartEvent read FOnWorkStart write FOnWorkStart; + property OnWork: TGeneratorWorkEvent read FOnWork write FOnWork; + property OnWorkEnd: TNotifyEvent read FOnWorkEnd write FOnWorkEnd; + end; + +implementation + +uses + System.SysUtils, System.Variants, System.TypInfo, System.Generics.Defaults, untHelperClasses, + untInstructionFilters; + +{$REGION 'Const: JSON strings for TOpcodeExtensions'} +const + SExtInstructionMode: array[TExtInstructionMode] of String = ( + 'neutral', + 'require64', + 'exclude64' + ); + + SExtMandatoryPrefix: array[TExtMandatoryPrefix] of String = ( + 'none', + '66', + 'f3', + 'f2' + ); + + SExtModrmMod: array[TExtModrmMod] of String = ( + 'neutral', + 'memory', + 'register' + ); + + SExtModrmReg: array[TExtModrmReg] of String = ( + 'neutral', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7' + ); + + SExtModrmRm: array[TExtModrmRm] of String = ( + 'neutral', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7' + ); + + SExtOperandSize: array[TExtOperandSize] of String = ( + 'default', + '16', + '32' + ); + + SExtAddressSize: array[TExtAddressSize] of String = ( + 'default', + '16', + '32', + '64' + ); + + SExtBitFilter: array[TExtBitFilter] of String = ( + 'rex_w', + 'vex_l', + 'evex_l2', + 'evex_b' + ); +{$ENDREGION} + +{$REGION 'Const: JSON strings for TCPUIDFeatureFlags'} +const + SCPUIDFeatureFlag: array[TCPUIDFeatureFlag] of String = ( + '3dnow', + 'adx', + 'aesni', + 'avx', + 'avx2', + 'avx512bw', + 'avx512cd', + 'avx512dq', + 'avx512er', + 'avx512f', + 'avx512pf', + 'avx512vl', + 'bmi1', + 'bmi2', + 'cmov', + 'cmpxchg16b', + 'f16c', + 'fma', + 'fma4', + 'fsgsbase', + 'hle', + 'lzcnt', + 'mmx', + 'movbe', + 'mpx', + 'pclmul', + 'popcnt', + 'prefetchw', + 'rdrand', + 'rdseed', + 'rtm', + 'sha', + 'sse1', + 'sse2', + 'sse3', + 'sse41', + 'sse42', + 'sse4a', + 'ssse3', + 'tbm', + 'tsx', + 'xop', + 'fxsr', + 'lahfsahf', + 'xsave', + 'xsaves', + 'xsavec', + 'xsaveopt', + 'mfence', + 'vbmi', + 'ifma' + ); +{$ENDREGION} + +{$REGION 'Const: JSON strings for TX86Registers'} +const + SX86Register: array[TX86Register] of String = ( + 'none', + // General purpose registers 64-bit + 'rax', 'rcx', 'rdx', 'rbx', 'rsp', 'rbp', 'rsi', 'rdi', + 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', + // General purpose registers 32-bit + 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi', + 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', + // General purpose registers 16-bit + 'ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di', + 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', + // General purpose registers 8-bit + 'al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh', + 'spl', 'bpl', 'sil', 'dil', + 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', + // Floating point legacy registers + 'st0', 'st1', 'st2', 'st3', 'st4', 'st5', 'st6', 'st7', + // Floating point multimedia registers + 'mm0', 'mm1', 'mm2', 'mm3', 'mm4', 'mm5', 'mm6', 'mm7', + // Floating point vector registers 512-bit + 'zmm0', 'zmm1', 'zmm2', 'zmm3', 'zmm4', 'zmm5', 'zmm6', 'zmm7', + 'zmm8', 'zmm9', 'zmm10', 'zmm11', 'zmm12', 'zmm13', 'zmm14', 'zmm15', + 'zmm16', 'zmm17', 'zmm18', 'zmm19', 'zmm20', 'zmm21', 'zmm22', 'zmm23', + 'zmm24', 'zmm25', 'zmm26', 'zmm27', 'zmm28', 'zmm29', 'zmm30', 'zmm31', + // Floating point vector registers 256-bit + 'ymm0', 'ymm1', 'ymm2', 'ymm3', 'ymm4', 'ymm5', 'ymm6', 'ymm7', + 'ymm8', 'ymm9', 'ymm10', 'ymm11', 'ymm12', 'ymm13', 'ymm14', 'ymm15', + 'ymm16', 'ymm17', 'ymm18', 'ymm19', 'ymm20', 'ymm21', 'ymm22', 'ymm23', + 'ymm24', 'ymm25', 'ymm26', 'ymm27', 'ymm28', 'ymm29', 'ymm30', 'ymm31', + // Floating point vector registers 128-bit + 'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7', + 'xmm8', 'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14', 'xmm15', + 'xmm16', 'xmm17', 'xmm18', 'xmm19', 'xmm20', 'xmm21', 'xmm22', 'xmm23', + 'xmm24', 'xmm25', 'xmm26', 'xmm27', 'xmm28', 'xmm29', 'xmm30', 'xmm31', + // Special registers + 'rflags', 'eflags', 'flags', 'rip', 'eip', 'ip', + // Segment registers + 'es', 'cs', 'ss', 'ds', 'gs', 'fs', + // Control registers + 'cr0', 'cr1', 'cr2', 'cr3', 'cr4', 'cr5', 'cr6', 'cr7', + 'cr8', 'cr9', 'cr10', 'cr11', 'cr12', 'cr13', 'cr14', 'cr15', + // Debug registers + 'dr0', 'dr1', 'dr2', 'dr3', 'dr4', 'dr5', 'dr6', 'dr7', + 'dr8', 'dr9', 'dr10', 'dr11', 'dr12', 'dr13', 'dr14', 'dr15', + // Mask registers + 'k0', 'k1', 'k2', 'k3', 'k4', 'k5', 'k6', 'k7', + // Bounds registers + 'bnd0', 'bnd1', 'bnd2', 'bnd3' + ); +{$ENDREGION} + +{$REGION 'Const: JSON strings for TX86Flags'} +const + SX86FlagValue: array[TX86FlagValue] of String = ( + 'unused', + 'tested', + 'modified', + 'reset', + 'set', + 'undefined', + 'prior' + ); +{$ENDREGION} + +{$REGION 'Const: JSON strings for TInstructionOperand'} +const + SOperandType: array[TOperandType] of String = ( + 'unused', + 'gpr8', + 'gpr16', + 'gpr32', + 'gpr64', + 'fpr', + 'vr64', + 'vr128', + 'vr256', + 'vr512', + 'cr', + 'dr', + 'sreg', + 'mskr', + 'bndr', + 'mem', + 'mem8', + 'mem16', + 'mem32', + 'mem64', + 'mem80', + 'mem128', + 'mem256', + 'mem512', + 'mem32bcst2', + 'mem32bcst4', + 'mem32bcst8', + 'mem32bcst16', + 'mem64bcst2', + 'mem64bcst4', + 'mem64bcst8', + 'mem64bcst16', + 'mem32vsibx', + 'mem32vsiby', + 'mem32vsibz', + 'mem64vsibx', + 'mem64vsiby', + 'mem64vsibz', + 'mem1616', + 'mem1632', + 'mem1664', + 'mem112', + 'mem224', + 'imm8', + 'imm8u', + 'imm16', + 'imm32', + 'imm64', + 'rel8', + 'rel16', + 'rel32', + 'rel64', + 'ptr1616', + 'ptr1632', + 'ptr1664', + 'moffs16', + 'moffs32', + 'moffs64', + 'srcidx8', + 'srcidx16', + 'srcidx32', + 'srcidx64', + 'dstidx8', + 'dstidx16', + 'dstidx32', + 'dstidx64', + '1', + 'al', + 'cl', + 'ax', + 'dx', + 'eax', + 'rax', + 'st0', + 'es', + 'ss', + 'cs', + 'ds', + 'fs', + 'gs' + ); + + SOperandEncoding: array[TOperandEncoding] of String = ( + 'none', + 'modrm_reg', + 'modrm_rm', + 'modrm_rm_cd1', + 'modrm_rm_cd2', + 'modrm_rm_cd4', + 'modrm_rm_cd8', + 'modrm_rm_cd16', + 'modrm_rm_cd32', + 'modrm_rm_cd64', + 'opcode', + 'vex_vvvv', + 'evex_aaa', + 'imm8', + 'imm16', + 'imm32', + 'imm64' + ); + + SOperandAccessMode: array[TOperandAccessMode] of String = ( + 'read', + 'write', + 'readwrite' + ); +{$ENDREGION} + +{$REGION 'Const: JSON strings for TInstructionDefinition'} +const + SInstructionEncoding: array[TInstructionEncoding] of String = ( + 'default', + '3dnow', + 'xop', + 'vex', + 'evex' + ); + + SOpcodeMap: array[TOpcodeMap] of String = ( + 'default', + '0f', + '0f38', + '0f3a', + 'xop8', + 'xop9', + 'xopa' + ); + + SInstructionDefinitionFlag: array[TInstructionDefinitionFlag] of String = ( + 'conflict', + 'accepts_lock', + 'accepts_rep', + 'accepts_xacquire', + 'accepts_xrelease', + 'accepts_evex_aaa', + 'accepts_evex_z', + 'has_evex_bc', + 'has_evex_rc', + 'has_evex_sae' + ); +{$ENDREGION} + +{$REGION 'Class: TJSONEnumHelper'} +type + TJSONEnumHelper = record + private + class function ReadString(JSON: PJSONVariantData; const Name, Default: String; + const LowerCase: Boolean = true): String; static; inline; + public + class function ReadEnumValueFromString(JSON: PJSONVariantData; const Name: String; + const Values: array of String): Integer; static; + end; + +class function TJSONEnumHelper.ReadEnumValueFromString(JSON: PJSONVariantData; const Name: String; + const Values: array of String): Integer; +begin + Result := TStringHelper.IndexStr(ReadString(JSON, Name, Values[0]), Values); + if (Result < 0) then + begin + raise Exception.CreateFmt('The "%s" field contains an invalid enum value.', [Name]); + end; +end; + +class function TJSONEnumHelper.ReadString(JSON: PJSONVariantData; const Name, Default: String; + const LowerCase: Boolean): String; +var + V: Variant; +begin + V := JSON^.Value[Name]; + if (VarIsEmpty(V)) then + begin + Exit(Default); + end; + Result := V; + if (LowerCase) then + begin + TStringHelper.AnsiLowerCase(Result); + end; +end; +{$ENDREGION} + +{$REGION 'Class: TOpcodeExtensions'} +procedure TOpcodeExtensions.AssignTo(Dest: TPersistent); +var + D: TOpcodeExtensions; +begin + if (Dest is TOpcodeExtensions) then + begin + D := Dest as TOpcodeExtensions; + D.FMode := FMode; + D.FMandatoryPrefix := FMandatoryPrefix; + D.FModrmMod := FModrmMod; + D.FModrmReg := FModrmReg; + D.FModrmRm := FModrmRm; + D.FOperandSize := FOperandSize; + D.FAddressSize := FAddressSize; + D.FBitFilters := FBitFilters; + D.Changed; + end else inherited; +end; + +procedure TOpcodeExtensions.Changed; +begin + FDefinition.UpdatePosition; +end; + +constructor TOpcodeExtensions.Create(Definition: TInstructionDefinition); +begin + inherited Create; + FDefinition := Definition; +end; + +function TOpcodeExtensions.Equals(const Value: TOpcodeExtensions): Boolean; +begin + Result := + (Value.FMode = FMode) and (Value.FMandatoryPrefix = FMandatoryPrefix) and + (Value.FModrmMod = FModrmMod) and (Value.FModrmReg = FModrmReg) and + (Value.FModrmRm = FModrmRm) and (Value.FOperandSize = FOperandSize) and + (Value.FAddressSize = FAddressSize) and (Value.FBitFilters = FBitFilters); +end; + +procedure TOpcodeExtensions.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); +var + V, A: PJSONVariantData; + I: Integer; + F: TExtBitFilter; + BitFilters: TExtBitFilters; +begin + V := JSON.Data(FieldName); + if (Assigned(V)) then + begin + if (V^.Kind <> jvObject) then + begin + raise Exception.CreateFmt('The "%s" field is not a valid JSON object.', [FieldName]); + end; + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'mode', SExtInstructionMode); + SetMode(TExtInstructionMode(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'prefix', SExtMandatoryPrefix); + SetPrefix(TExtMandatoryPrefix(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'modrm_mod', SExtModrmMod); + SetModrmMod(TExtModrmMod(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'modrm_reg', SExtModrmReg); + SetModrmReg(TExtModrmReg(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'modrm_rm', SExtModrmRm); + SetModrmRm(TExtModrmRm(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'opsize', SExtOperandSize); + SetOperandSize(TExtOperandSize(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'adsize', SExtAddressSize); + SetAddressSize(TExtAddressSize(I)); + A := V^.Data('bitfilters'); + if (Assigned(A)) then + begin + if (A^.Kind <> jvArray) then + begin + raise Exception.Create('The "prefix_flags" field is not a valid JSON array.'); + end; + BitFilters := []; + for I := 0 to A^.Count - 1 do + begin + for F := Low(SExtBitFilter) to High(SExtBitFilter) do + begin + if (LowerCase(A^.Item[I]) = SExtBitFilter[F]) then + begin + BitFilters := BitFilters + [F]; + Break; + end; + end; + end; + SetBitFilters(BitFilters); + end; + end; +end; + +procedure TOpcodeExtensions.SaveToJSON(JSON: PJSONVariantData; const FieldName: String); +var + V, A: TJSONVariantData; + F: TExtBitFilter; +begin + V.Init; + if (FMode <> imNeutral) then + V.AddNameValue('mode', SExtInstructionMode[FMode]); + if (FMandatoryPrefix <> mpNone) then + V.AddNameValue('prefix', SExtMandatoryPrefix[FMandatoryPrefix]); + if (FModrmMod <> mdNeutral) then + V.AddNameValue('modrm_mod', SExtModrmMod[FModrmMod]); + if (FModrmRm <> rmNeutral) then + V.AddNameValue('modrm_rm', SExtModrmRm[FModrmRm]); + if (FModrmReg <> rgNeutral) then + V.AddNameValue('modrm_reg', SExtModrmReg[FModrmReg]); + if (FOperandSize <> osNeutral) then + V.AddNameValue('opsize', SExtOperandSize[FOperandSize]); + if (FAddressSize <> asNeutral) then + V.AddNameValue('adsize', SExtAddressSize[FAddressSize]); + A.Init; + for F in FBitFilters do + begin + A.AddValue(SExtBitFilter[F]); + end; + if (A.Count > 0) then + begin + V.AddNameValue('bitfilters', Variant(A)); + end; + if (V.Count > 0) then + begin + JSON^.AddNameValue(FieldName, Variant(V)); + end; +end; + +procedure TOpcodeExtensions.SetAddressSize(const Value: TExtAddressSize); +begin + if (FAddressSize <> Value) then + begin + FAddressSize := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetBitFilters(const Value: TExtBitFilters); +begin + if (FBitFilters <> Value) then + begin + FBitFilters := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetMandatoryPrefix(const Value: TExtMandatoryPrefix); +begin + if (FMandatoryPrefix <> Value) then + begin + FMandatoryPrefix := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetMode(const Value: TExtInstructionMode); +begin + if (FMode <> Value) then + begin + FMode := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetModrmMod(const Value: TExtModrmMod); +begin + if (FModrmMod <> Value) then + begin + FModrmMod := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetModrmReg(const Value: TExtModrmReg); +begin + if (FModrmReg <> Value) then + begin + FModrmReg := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetModrmRm(const Value: TExtModrmRm); +begin + if (FModrmRm <> Value) then + begin + FModrmRm := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetOperandSize(const Value: TExtOperandSize); +begin + if (FOperandSize <> Value) then + begin + FOperandSize := Value; + Changed; + end; +end; + +procedure TOpcodeExtensions.SetPrefix(const Value: TExtMandatoryPrefix); +begin + FMandatoryPrefix := Value; +end; +{$ENDREGION} + +{$REGION 'Class: TCPUIDFeatureFlags'} +procedure TCPUIDFeatureFlags.AssignTo(Dest: TPersistent); +var + D: TCPUIDFeatureFlags; +begin + if (Dest is TCPUIDFeatureFlags) then + begin + D := Dest as TCPUIDFeatureFlags; + D.SetFeatureFlags(FFeatureFlags); + end else inherited; +end; + +procedure TCPUIDFeatureFlags.Changed; +begin + FDefinition.UpdateValues; +end; + +constructor TCPUIDFeatureFlags.Create(Definition: TInstructionDefinition); +begin + inherited Create; + FDefinition := Definition; +end; + +function TCPUIDFeatureFlags.Equals(const Value: TCPUIDFeatureFlags): Boolean; +begin + Result := (Value.FFeatureFlags = FFeatureFlags); +end; + +procedure TCPUIDFeatureFlags.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); +var + A: PJSONVariantData; + I: Integer; + C: TCPUIDFeatureFlag; + Value: TCPUIDFeatureFlagSet; +begin + A := JSON.Data(FieldName); + if (Assigned(A)) then + begin + if (A^.Kind <> jvArray) then + begin + raise Exception.CreateFmt('The "%s" field is not a valid JSON array.', [FieldName]); + end; + Value := []; + for I := 0 to A^.Count - 1 do + begin + for C := Low(SCPUIDFeatureFlag) to High(SCPUIDFeatureFlag) do + begin + if (LowerCase(A^.Item[I]) = SCPUIDFeatureFlag[C]) then + begin + Value := Value + [C]; + Break; + end; + end; + end; + SetFeatureFlags(Value); + end; +end; + +procedure TCPUIDFeatureFlags.SaveToJSON(JSON: PJSONVariantData; const FieldName: String); +var + A: TJSONVariantData; + C: TCPUIDFeatureFlag; +begin + A.Init; + for C in FFeatureFlags do + begin + A.AddValue(SCPUIDFeatureFlag[C]); + end; + if (A.Count > 0) then + begin + JSON.AddNameValue(FieldName, Variant(A)); + end; +end; + +procedure TCPUIDFeatureFlags.SetFeatureFlags(const Value: TCPUIDFeatureFlagSet); +begin + if (FFeatureFlags <> Value) then + begin + FFeatureFlags := Value; + Changed; + end; +end; +{$ENDREGION} + +{$REGION 'Class: TX86Registers'} +procedure TX86Registers.AssignTo(Dest: TPersistent); +var + D: TX86Registers; +begin + if (Dest is TX86Registers) then + begin + D := Dest as TX86Registers; + D.SetRegisters(FRegisters); + end else inherited; +end; + +procedure TX86Registers.Changed; +begin + FDefinition.UpdateValues; +end; + +constructor TX86Registers.Create(Definition: TInstructionDefinition); +begin + inherited Create; + FDefinition := Definition; +end; + +function TX86Registers.Equals(const Value: TX86Registers): Boolean; +begin + Result := (Value.FRegisters = FRegisters); +end; + +procedure TX86Registers.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); +var + A: PJSONVariantData; + I: Integer; + R: TX86Register; + Value: TX86RegisterSet; +begin + A := JSON^.Data(FieldName); + if (Assigned(A)) then + begin + if (A^.Kind <> jvArray) then + begin + raise Exception.CreateFmt('The "%s" field is not a valid JSON array.', [FieldName]); + end; + Value := []; + for I := 0 to A^.Count - 1 do + begin + for R := Low(SX86Register) to High(SX86Register) do + begin + if (LowerCase(A^.Item[I]) = SX86Register[R]) then + begin + Value := Value + [R]; + Break; + end; + end; + end; + SetRegisters(Value); + end; +end; + +procedure TX86Registers.SaveToJSON(JSON: PJSONVariantData; const FieldName: String); +var + A: TJSONVariantData; + R: TX86Register; +begin + A.Init; + for R in FRegisters do + begin + A.AddValue(SX86Register[R]); + end; + if (A.Count > 0) then + begin + JSON.AddNameValue(FieldName, Variant(A)); + end; +end; + +procedure TX86Registers.SetRegisters(const Value: TX86RegisterSet); +begin + if (FRegisters <> Value) then + begin + FRegisters := Value; + Changed; + end; +end; +{$ENDREGION} + +{$REGION 'Class: TX86Flags'} +procedure TX86Flags.AssignTo(Dest: TPersistent); +var + D: TX86Flags; +begin + if (Dest is TX86Flags) then + begin + D := Dest as TX86Flags; + D.FCF := FCF; + D.FPF := FPF; + D.FAF := FAF; + D.FZF := FZF; + D.FSF := FSF; + D.FTF := FTF; + D.FIF := FIF; + D.FDF := FDF; + D.FOF := FOF; + D.FRF := FRF; + D.FVM := FVM; + D.FAC := FAC; + D.FVIF := FVIF; + D.FVIP := FVIP; + D.FID := FID; + D.Changed; + end else inherited; +end; + +procedure TX86Flags.Changed; +begin + FDefinition.UpdateValues; +end; + +constructor TX86Flags.Create(Definition: TInstructionDefinition); +begin + inherited Create; + FDefinition := Definition; +end; + +function TX86Flags.Equals(const Value: TX86Flags): Boolean; +begin + Result := (Value.FCF = FCF) and (Value.FPF = FPF) and (Value.FAF = FAF) and + (Value.FZF = FZF) and (Value.FSF = FSF) and (Value.FTF = FTF) and (Value.FIF = FIF) and + (Value.FDF = FDF) and (Value.FOF = FOF) and (Value.FRF = FRF) and (Value.FVM = FVM) and + (Value.FAC = FAC) and (Value.FVIF = FVIF) and (Value.FVIP = FVIP) and (Value.FID = FID); +end; + +procedure TX86Flags.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); +var + C: PJSONVariantData; + F: array[0..14] of ^TX86FlagValue; + N: array[0..14] of String; + I, J: Integer; +begin + C := JSON.Data(FieldName); + if (Assigned(C)) then + begin + if (C^.Kind <> jvObject) then + begin + raise Exception.CreateFmt('The "%s" field is not a valid JSON object.', [FieldName]); + end; + F[ 0] := @FCF; F[ 1] := @FPF; F[ 2] := @FAF; F[ 3] := @FZF; F[ 4] := @FSF; + F[ 5] := @FTF; F[ 6] := @FIF; F[ 7] := @FDF; F[ 8] := @FOF; F[ 9] := @FRF; + F[10] := @FVM; F[11] := @FAC; F[12] := @FVIF; F[13] := @FVIP; F[14] := @FID; + N[ 0] := 'cf'; N[ 1] := 'pf'; N[ 2] := 'af'; N[ 3] := 'zf'; N[ 4] := 'sf'; + N[ 5] := 'tf'; N[ 6] := 'if'; N[ 7] := 'df'; N[ 8] := 'of'; N[ 9] := 'rf'; + N[10] := 'vm'; N[11] := 'ac'; N[12] := 'vif'; N[13] := 'vip'; N[14] := 'id'; + for I := Low(N) to High(N) do + begin + J := TJSONEnumHelper.ReadEnumValueFromString(C, N[I], SX86FlagValue); + F[I]^ := TX86FlagValue(J); + end; + Changed; + end; +end; + +procedure TX86Flags.SaveToJSON(JSON: PJSONVariantData; const FieldName: String); +var + F: array[0..14] of ^TX86FlagValue; + N: array[0..14] of String; + J: TJSONVariantData; + I: Integer; +begin + F[ 0] := @FCF; F[ 1] := @FPF; F[ 2] := @FAF; F[ 3] := @FZF; F[ 4] := @FSF; + F[ 5] := @FTF; F[ 6] := @FIF; F[ 7] := @FDF; F[ 8] := @FOF; F[ 9] := @FRF; + F[10] := @FVM; F[11] := @FAC; F[12] := @FVIF; F[13] := @FVIP; F[14] := @FID; + N[ 0] := 'cf'; N[ 1] := 'pf'; N[ 2] := 'af'; N[ 3] := 'zf'; N[ 4] := 'sf'; + N[ 5] := 'tf'; N[ 6] := 'if'; N[ 7] := 'df'; N[ 8] := 'of'; N[ 9] := 'rf'; + N[10] := 'vm'; N[11] := 'ac'; N[12] := 'vif'; N[13] := 'vip'; N[14] := 'id'; + J.Init; + for I := Low(N) to High(N) do + begin + if (F[I]^ <> fvUnused) then + begin + J.AddNameValue(N[I], SX86FlagValue[F[I]^]); + end; + end; + if (J.Count > 0) then + begin + JSON.AddNameValue(FieldName, Variant(J)); + end; +end; + +procedure TX86Flags.SetAC(const Value: TX86FlagValue); +begin + if (FAC <> Value) then + begin + FAC := Value; + Changed; + end; +end; + +procedure TX86Flags.SetAF(const Value: TX86FlagValue); +begin + if (FAF <> Value) then + begin + FAF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetCF(const Value: TX86FlagValue); +begin + if (FCF <> Value) then + begin + FCF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetDF(const Value: TX86FlagValue); +begin + if (FDF <> Value) then + begin + FDF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetID(const Value: TX86FlagValue); +begin + if (FID <> Value) then + begin + FID := Value; + Changed; + end; +end; + +procedure TX86Flags.SetIF(const Value: TX86FlagValue); +begin + if (FIF <> Value) then + begin + FIF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetOF(const Value: TX86FlagValue); +begin + if (FOF <> Value) then + begin + FOF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetPF(const Value: TX86FlagValue); +begin + if (FPF <> Value) then + begin + FPF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetRF(const Value: TX86FlagValue); +begin + if (FRF <> Value) then + begin + FRF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetSF(const Value: TX86FlagValue); +begin + if (FSF <> Value) then + begin + FSF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetTF(const Value: TX86FlagValue); +begin + if (FTF <> Value) then + begin + FTF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetVIF(const Value: TX86FlagValue); +begin + if (FVIF <> Value) then + begin + FVIF := Value; + Changed; + end; +end; + +procedure TX86Flags.SetVIP(const Value: TX86FlagValue); +begin + if (FVIP <> Value) then + begin + FVIP := Value; + Changed; + end; +end; + +procedure TX86Flags.SetVM(const Value: TX86FlagValue); +begin + if (FVM <> Value) then + begin + FVM := Value; + Changed; + end; +end; + +procedure TX86Flags.SetZF(const Value: TX86FlagValue); +begin + if (FZF <> Value) then + begin + FZF := Value; + Changed; + end; +end; +{$ENDREGION} + +{$REGION 'Class: TInstructionOperand'} +procedure TInstructionOperand.AssignTo(Dest: TPersistent); +var + D: TInstructionOperand; +begin + if (Dest is TInstructionOperand) then + begin + D := Dest as TInstructionOperand; + D.FType := FType; + D.FEncoding := FEncoding; + D.FAccessMode := FAccessMode; + D.Changed; + end else inherited; +end; + +procedure TInstructionOperand.Changed; +begin + FOperands.Changed; +end; + +constructor TInstructionOperand.Create(Operands: TInstructionOperands); +begin + inherited Create; + FOperands := Operands; +end; + +function TInstructionOperand.Equals(const Value: TInstructionOperand): Boolean; +begin + Result := + (Value.FType = FType) and (Value.FEncoding = FEncoding) and (Value.FAccessMode = FAccessMode); +end; + +function TInstructionOperand.GetConflictState: Boolean; +begin + Result := false; + case FType of + optGPR8, + optGPR16: + Result := not (FEncoding in [opeModrmReg, opeModrmRm, opeOpcodeBits]); + optGPR32, + optGPR64: + Result := not (FEncoding in [opeModrmReg, opeModrmRm, opeOpcodeBits, opeVexVVVV]); + optFPR: + Result := not (FEncoding in [opeModrmRm]); + optVR64: + Result := not (FEncoding in [opeModrmReg, opeModrmRm]); + optVR128, + optVR256, + optVR512: + Result := not (FEncoding in [opeModrmReg, opeModrmRm, opeVexVVVV, opeImm8, opeModrmRmCD1, + opeModrmRmCD2, opeModrmRmCD4, opeModrmRmCD8, opeModrmRmCD16, opeModrmRmCD32, + opeModrmRmCD64]); + optCR, + optDR, + optSREG: + Result := not (FEncoding in [opeModrmReg]); + optMSKR: + Result := not (FEncoding in [opeModrmReg, opeModrmRm, opeVexVVVV]); + optBNDR: + Result := not (FEncoding in [opeModrmReg, opeModrmRm]); + optMem: + Result := not (FEncoding in [opeModrmRm]); + optMem8, + optMem16, + optMem32, + optMem64: + Result := not (FEncoding in [opeModrmRm, opeModrmRmCD1, opeModrmRmCD2, opeModrmRmCD4, + opeModrmRmCD8, opeModrmRmCD16, opeModrmRmCD32, opeModrmRmCD64]); + optMem80: + Result := not (FEncoding in [opeModrmRm]); + optMem128, + optMem256, + optMem512: + Result := not (FEncoding in [opeModrmRm, opeModrmRmCD1, opeModrmRmCD2, opeModrmRmCD4, + opeModrmRmCD8, opeModrmRmCD16, opeModrmRmCD32, opeModrmRmCD64]); + optMem32Bcst2, + optMem32Bcst4, + optMem32Bcst8, + optMem32Bcst16, + optMem64Bcst2, + optMem64Bcst4, + optMem64Bcst8, + optMem64Bcst16: + Result := not (FEncoding in [opeModrmRmCD1, opeModrmRmCD2, opeModrmRmCD4, opeModrmRmCD8, + opeModrmRmCD16, opeModrmRmCD32, opeModrmRmCD64]); + optMem32VSIBX, + optMem32VSIBY, + optMem32VSIBZ, + optMem64VSIBX, + optMem64VSIBY, + optMem64VSIBZ: + Result := not (FEncoding in [opeModrmRm, opeModrmRmCD1, opeModrmRmCD2, opeModrmRmCD4, + opeModrmRmCD8, opeModrmRmCD16, opeModrmRmCD32, opeModrmRmCD64]); + optMem1616, + optMem1632, + optMem1664, + optMem112, + optMem224: + Result := not (FEncoding in [opeModrmRm]); + optImm8, + optImm8U: + Result := not (FEncoding in [opeImm8]); + optImm16: + Result := not (FEncoding in [opeImm8, opeImm16]); + optImm32: + Result := not (FEncoding in [opeImm8, opeImm32]); + optImm64: + Result := not (FEncoding in [opeImm8, opeImm32, opeImm64]); + optRel8: + Result := not (FEncoding in [opeImm8]); + optRel16: + Result := not (FEncoding in [opeImm16]); + optRel32: + Result := not (FEncoding in [opeImm32]); + optRel64: + Result := not (FEncoding in [opeImm64]); + optPtr1616, + optPtr1632, + optPtr1664, + optMoffs16, + optMoffs32, + optMoffs64, + optSrcIndex8, + optSrcIndex16, + optSrcIndex32, + optSrcIndex64, + optDstIndex8, + optDstIndex16, + optDstIndex32, + optDstIndex64, + optFixed1, + optFixedAL, + optFixedCL, + optFixedAX, + optFixedDX, + optFixedEAX, + optFixedRAX, + optFixedST0, + optFixedES, + optFixedSS, + optFixedCS, + optFixedDS, + optFixedFS, + optFixedGS: + Result := not (FEncoding in [opeNone]); + end; +end; + +function TInstructionOperand.GetDescription(IncludeAccessMode: Boolean): String; +begin + if (GetConflictState) then + begin + Result := 'invalid'; + Exit; + end; + Result := ''; + if (FType <> optUnused) then + begin + case FType of + optGPR8 : Result := 'GPR8'; + optGPR16 : Result := 'GPR16'; + optGPR32 : Result := 'GPR32'; + optGPR64 : Result := 'GPR64'; + optFPR : Result := 'ST(i)'; + optVR64 : Result := 'MM64'; + optVR128 : Result := 'XMM128'; + optVR256 : Result := 'YMM256'; + optVR512 : Result := 'ZMM512'; + optMSKR : Result := 'MASK'; + optBNDR : Result := 'BND'; + optCR : Result := 'CR'; + optDR : Result := 'DR'; + optMem : Result := 'mem'; + optMem8 : Result := 'mem8'; + optMem16 : Result := 'mem16'; + optMem32 : Result := 'mem32'; + optMem64 : Result := 'mem64'; + optMem80 : Result := 'mem80'; + optMem128 : Result := 'mem128'; + optMem256 : Result := 'mem256'; + optMem512 : Result := 'mem512'; + optMem32Bcst2: Result := 'mem32bcst2'; + optMem32Bcst4: Result := 'mem32bcst4'; + optMem32Bcst8: Result := 'mem32bcst8'; + optMem32Bcst16: Result := 'mem32bcst16'; + optMem64Bcst2: Result := 'mem64bcst2'; + optMem64Bcst4: Result := 'mem64bcst4'; + optMem64Bcst8: Result := 'mem64bcst8'; + optMem64Bcst16: Result := 'mem64bcst16'; + optMem112 : Result := 'mem112'; + optMem224 : Result := 'mem224'; + optImm8 : Result := 'imm8'; + optImm16 : Result := 'imm16'; + optImm32 : Result := 'imm32'; + optImm64 : Result := 'imm64'; + optImm8U : Result := 'imm8u'; + optRel8 : Result := 'rel8'; + optRel16 : Result := 'rel16'; + optRel32 : Result := 'rel32'; + optRel64 : Result := 'rel64'; + optPtr1616 : Result := 'ptr16:16'; + optPtr1632 : Result := 'ptr16:32'; + optPtr1664 : Result := 'ptr16:64'; + optMoffs16 : Result := 'moffs16'; + optMoffs32 : Result := 'moffs32'; + optMoffs64 : Result := 'moffs64'; + optSrcIndex8 : Result := 'srcidx8'; + optSrcIndex16: Result := 'srcidx16'; + optSrcIndex32: Result := 'srcidx32'; + optSrcIndex64: Result := 'srcidx64'; + optDstIndex8 : Result := 'dstidx8'; + optDstIndex16: Result := 'dstidx16'; + optDstIndex32: Result := 'dstidx32'; + optDstIndex64: Result := 'dstidx64'; + optSREG : Result := 'SEG'; + optMem1616 : Result := 'mem16:16'; + optMem1632 : Result := 'mem16:32'; + optMem1664 : Result := 'mem16:64'; + optMem32VSIBX : Result := 'mem32vsibx'; + optMem32VSIBY : Result := 'mem32vsiby'; + optMem32VSIBZ : Result := 'mem32vsibz'; + optMem64VSIBX : Result := 'mem64vsibx'; + optMem64VSIBY : Result := 'mem64vsiby'; + optMem64VSIBZ : Result := 'mem64vsibz'; + optFixed1 : Result := '1'; + optFixedAL : Result := 'AL'; + optFixedCL : Result := 'CL'; + optFixedAX : Result := 'AX'; + optFixedDX : Result := 'DX'; + optFixedEAX : Result := 'EAX'; + optFixedRAX : Result := 'RAX'; + optFixedES : Result := 'ES'; + optFixedCS : Result := 'CS'; + optFixedSS : Result := 'SS'; + optFixedDS : Result := 'DS'; + optFixedGS : Result := 'GS'; + optFixedFS : Result := 'FS'; + optFixedST0 : Result := 'ST0'; + end; + if (IncludeAccessMode) then + begin + case FAccessMode of + opaRead : Result := Result + ' (r)'; + opaWrite : Result := Result + ' (w)'; + opaReadWrite: Result := Result + ' (r, w)'; + end; + end; + end; +end; + +procedure TInstructionOperand.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); +var + V: PJSONVariantData; + I: Integer; +begin + V := JSON^.Data(FieldName); + if Assigned(V) then + begin + if (V^.Kind <> jvObject) then + begin + raise Exception.CreateFmt('The "%s" field is not a valid JSON object.', [FieldName]); + end; + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'type', SOperandType); + SetType(TOperandType(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'encoding', SOperandEncoding); + SetEncoding(TOperandEncoding(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(V, 'accessmode', SOperandAccessMode); + SetAccessMode(TOperandAccessMode(I)); + end; +end; + +procedure TInstructionOperand.SaveToJSON(JSON: PJSONVariantData; const FieldName: String); +var + V: TJSONVariantData; +begin + if (FType <> optUnused) then + begin + V.Init; + V.AddNameValue('type', SOperandType[FType]); + if (FEncoding <> opeNone) then V.AddNameValue('encoding', SOperandEncoding[FEncoding]); + if (FAccessMode <> opaRead) then V.AddNameValue('accessmode', SOperandAccessMode[FAccessMode]); + JSON^.AddNameValue(FieldName, Variant(V)); + end; +end; + +procedure TInstructionOperand.SetAccessMode(const Value: TOperandAccessMode); +begin + if (FAccessMode <> Value) then + begin + FAccessMode := Value; + Changed; + end; +end; + +procedure TInstructionOperand.SetEncoding(const Value: TOperandEncoding); +begin + if (FEncoding <> Value) then + begin + FEncoding := Value; + Changed; + end; +end; + +procedure TInstructionOperand.SetType(const Value: TOperandType); +begin + if (FType <> Value) then + begin + case Value of + optGPR8: ; + optGPR16: ; + optGPR32: ; + optGPR64: ; + optVR64: ; + optVR128: ; + optVR256: ; + optVR512: ; + optFPR: + FEncoding := opeModrmRm; + optCR: ; + optDR: ; + optSREG: ; + optMSKR: ; + optBNDR: ; + optMem: ; + optMem8: ; + optMem16: ; + optMem32: ; + optMem64: ; + optMem80: ; + optMem128: ; + optMem256: ; + optMem512: ; + optMem32Bcst2: ; + optMem32Bcst4: ; + optMem32Bcst8: ; + optMem32Bcst16: ; + optMem64Bcst2: ; + optMem64Bcst4: ; + optMem64Bcst8: ; + optMem64Bcst16: ; + optMem32VSIBX: ; + optMem32VSIBY: ; + optMem32VSIBZ: ; + optMem64VSIBX: ; + optMem64VSIBY: ; + optMem64VSIBZ: ; + optMem1616: ; + optMem1632: ; + optMem1664: ; + optMem112: ; + optMem224: ; + optImm8: ; + optImm8U: ; + optImm16: ; + optImm32: ; + optImm64: ; + optRel8: ; + optRel16: ; + optRel32: ; + optRel64: ; + optPtr1616: ; + optPtr1632: ; + optPtr1664: ; + optMoffs16: ; + optMoffs32: ; + optMoffs64: ; + optSrcIndex8: ; + optSrcIndex16: ; + optSrcIndex32: ; + optSrcIndex64: ; + optDstIndex8: ; + optDstIndex16: ; + optDstIndex32: ; + optDstIndex64: ; + optFixed1: ; + optFixedAL: ; + optFixedCL: ; + optFixedAX: ; + optFixedDX: ; + optFixedEAX: ; + optFixedRAX: ; + optFixedST0: ; + optFixedES: ; + optFixedSS: ; + optFixedCS: ; + optFixedDS: ; + optFixedFS: ; + optFixedGS: ; + end; + {case Value of + optUnused: + FEncoding := opeNone; + optGPR8, + optGPR16, + optGPR32, + optGPR64, + optVR64, + optVR128, + optVR256, + optVR512, + optBNDR, + optCR, + optDR: + if (FEncoding <> opeModrmRm) then + begin + FEncoding := opeModrmReg; + end; + optMSKR: + if (FEncoding <> opeModrmRm) and (FEncoding <> opeVexVVVV) then + begin + FEncoding := opeModrmReg; + end; + optFPR: + FEncoding := opeModrmRm; + optMem, + optMem8, + optMem16, + optMem32, + optMem64, + optMem80, + optMem128, + optMem256, + optMem512, + optMem1616, + optMem1632, + optMem1664, + optMem32VSIBX, + optMem32VSIBY, + optMem32VSIBZ, + optMem64VSIBX, + optMem64VSIBY, + optMem64VSIBZ, + optMem32Bcst2, + optMem32Bcst4, + optMem32Bcst8, + optMem32Bcst16, + optMem64Bcst2, + optMem64Bcst4, + optMem64Bcst8, + optMem64Bcst16, + optMem112, + optMem224: + if not (FEncoding in [opeModrmRm, opeModrmRmCD1, opeModrmRmCD2, opeModrmRmCD4, + opeModrmRmCD8, opeModrmRmCD16, opeModrmRmCD32, opeModrmRmCD64]) then + begin + FEncoding := opeModrmRm; + end; + optImm8: + FEncoding := opeImm8; + optImm16: + FEncoding := opeImm16; + optImm32: + FEncoding := opeImm32; + optImm64: + if (FEncoding <> opeImm32) then + begin + FEncoding := opeImm64; + end; + optImm8U: + FEncoding := opeImm8; + optRel8: + FEncoding := opeImm8; + optRel16: + FEncoding := opeImm16; + optRel32: + FEncoding := opeImm32; + optRel64: + if (FEncoding <> opeImm32) then // TODO: ? + begin + FEncoding := opeImm64; + end; + optPtr1616, + optPtr1632, + optPtr1664: + FEncoding := opeNone; + optMoffs16, + optMoffs32, + optMoffs64: + FEncoding := opeNone; + optSREG: + FEncoding := opeModrmReg; + optSrcIndex8, + optSrcIndex16, + optSrcIndex32, + optSrcIndex64, + optDstIndex8, + optDstIndex16, + optDstIndex32, + optDstIndex64, + optFixed1, + optFixedAL, + optFixedCL, + optFixedAX, + optFixedDX, + optFixedEAX, + optFixedRAX, + optFixedCS, + optFixedSS, + optFixedDS, + optFixedES, + optFixedFS, + optFixedGS, + optFixedST0: + FEncoding := opeNone; + end;} + FType := Value; + Changed; + end; +end; +{$ENDREGION} + +{$REGION 'Class: TInstructionOperands'} +procedure TInstructionOperands.AssignTo(Dest: TPersistent); +var + D: TInstructionOperands; +begin + if (Dest is TInstructionOperands) then + begin + D := Dest as TInstructionOperands; + D.FOperandA.Assign(FOperandA); + D.FOperandB.Assign(FOperandB); + D.FOperandC.Assign(FOperandC); + D.FOperandD.Assign(FOperandD); + D.Changed; + end else inherited; +end; + +procedure TInstructionOperands.Changed; +{var + A: array[0..3] of TInstructionOperand; + I, J: Integer; +begin + FHasConflicts := false; + + // Check for invalid operand order + A[0] := FOperandA; A[1] := FOperandB; A[2] := FOperandC; A[3] := FOperandD; + for I := High(A) downto Low(A) do + begin + if (A[I].OperandType <> otUnused) then + begin + for J := I downto Low(A) do + begin + if (A[J].OperandType = otUnused) then + begin + FHasConflicts := true; + Break; + end; + end; + end; + if (FHasConflicts) then + begin + Break; + end; + end; } +begin + + // TODO: Determine Encoding + + FDefinition.UpdateValues; +end; + +constructor TInstructionOperands.Create(Definition: TInstructionDefinition); +begin + inherited Create; + FDefinition := Definition; + FOperandA := TInstructionOperand.Create(Self); + FOperandB := TInstructionOperand.Create(Self); + FOperandC := TInstructionOperand.Create(Self); + FOperandD := TInstructionOperand.Create(Self); +end; + +destructor TInstructionOperands.Destroy; +begin + if (Assigned(FOperandA)) then FOperandA.Free; + if (Assigned(FOperandB)) then FOperandB.Free; + if (Assigned(FOperandC)) then FOperandC.Free; + if (Assigned(FOperandD)) then FOperandD.Free; + inherited; +end; + +function TInstructionOperands.Equals(const Value: TInstructionOperands): Boolean; +begin + Result := + (Value.FOperandA.Equals(FOperandA)) and (Value.FOperandB.Equals(FOperandB)) and + (Value.FOperandC.Equals(FOperandC)) and (Value.FOperandD.Equals(FOperandD)); +end; + +function TInstructionOperands.GetConflictState: Boolean; +var + I: Integer; + EncReg, EncRm, EncVVVV, EncAAA: Integer; +begin + Result := + (FOperandA.HasConflicts) or (FOperandB.HasConflicts) or (FOperandC.HasConflicts) or + (OperandD.HasConflicts); + if (not Result) then + begin + EncReg := 0; EncRm := 0; EncVVVV := 0; EncAAA := 0; + for I := 0 to 3 do + begin + case GetOperandById(I).Encoding of + opeModrmReg : Inc(EncReg); + opeModrmRm, + opeModrmRmCD1, + opeModrmRmCD2, + opeModrmRmCD4, + opeModrmRmCD8, + opeModrmRmCD16, + opeModrmRmCD32, + opeModrmRmCD64: Inc(EncRm); + opeVexVVVV : Inc(EncVVVV); + opeEvexAAA : Inc(EncAAA); + end; + if (EncReg > 1) or (EncRm > 1) or (EncVVVV > 1) or (EncAAA > 1) then + begin + Result := true; + Break; + end; + end; + if (FDefinition.OpcodeExtensions.ModrmMod <> mdNeutral) and (EncReg > 0) and (EncRm = 0) then + begin + Exit(true) + end + // TODO: Check operand order, ... + end; +end; + +function TInstructionOperands.GetOperandById(Id: Integer): TInstructionOperand; +begin + Result := nil; + case Id of + 0: Result := FOperandA; + 1: Result := FOperandB; + 2: Result := FOperandC; + 3: Result := FOperandD; + end; +end; + +procedure TInstructionOperands.LoadFromJSON(JSON: PJSONVariantData; const FieldName: String); +var + V: PJSONVariantData; +begin + V := JSON^.Data(FieldName); + if Assigned(V) then + begin + if (V^.Kind <> jvObject) then + begin + raise Exception.CreateFmt('The "%s" field is not a valid JSON object.', [FieldName]); + end; + FOperandA.LoadFromJSON(V, 'operand1'); + FOperandB.LoadFromJSON(V, 'operand2'); + FOperandC.LoadFromJSON(V, 'operand3'); + FOperandD.LoadFromJSON(V, 'operand4'); + end; +end; + +procedure TInstructionOperands.SaveToJSON(JSON: PJSONVariantData; const FieldName: String); +var + V: TJSONVariantData; +begin + V.Init; + FOperandA.SaveToJSON(@V, 'operand1'); + FOperandB.SaveToJSON(@V, 'operand2'); + FOperandC.SaveToJSON(@V, 'operand3'); + FOperandD.SaveToJSON(@V, 'operand4'); + if (V.Count > 0) then + begin + JSON^.AddNameValue('operands', Variant(V)); + end; +end; +{$ENDREGION} + +{$REGION 'Class: TInstructionDefinition'} +procedure TInstructionDefinition.AssignTo(Dest: TPersistent); +var + D: TInstructionDefinition; +begin + if (Dest is TInstructionDefinition) then + begin + D := Dest as TInstructionDefinition; + D.BeginUpdate; + try + D.FMnemonic := FMnemonic; + D.FEncoding := FEncoding; + D.FOpcodeMap := FOpcodeMap; + D.FOpcode := FOpcode; + D.FExtensions.Assign(FExtensions); + D.FCPUID.Assign(FCPUID); + D.FOperands.Assign(FOperands); + D.FFlags := FFlags; + D.FImplicitRead.Assign(FImplicitRead); + D.FImplicitWrite.Assign(FImplicitWrite); + D.FX86Flags.Assign(FX86Flags); + D.FComment := FComment; + D.Update; + finally + D.EndUpdate; + end; + end else inherited; +end; + +procedure TInstructionDefinition.BeginUpdate; +begin + Inc(FUpdateCount); +end; + +constructor TInstructionDefinition.Create(Editor: TInstructionEditor; const Mnemonic: String); +begin + inherited Create; + FEditor := Editor; + if (Mnemonic = '') then + begin + raise Exception.Create('Mnemonic can not be empty.'); + end; + FMnemonic := Mnemonic; + FExtensions := TOpcodeExtensions.Create(Self); + FCPUID := TCPUIDFeatureFlags.Create(Self); + FOperands := TInstructionOperands.Create(Self); + FImplicitRead := TX86Registers.Create(Self); + FImplicitWrite := TX86Registers.Create(Self); + FX86Flags := TX86Flags.Create(Self); + // Insert definition into the definition list. This method does NOT insert the definition into + // the table structure + FEditor.RegisterDefinition(Self); +end; + +destructor TInstructionDefinition.Destroy; +begin + // Remove definition from the filter structure + if (Assigned(FParent)) then + begin + FEditor.RemoveDefinition(Self); + end; + // Remove definition from the definition list + FEditor.UnregisterDefinition(Self); + if (Assigned(FExtensions)) then FExtensions.Free; + if (Assigned(FCPUID)) then FCPUID.Free; + if (Assigned(FOperands)) then FOperands.Free; + if (Assigned(FImplicitRead)) then FImplicitRead.Free; + if (Assigned(FImplicitWrite)) then FImplicitWrite.Free; + if (Assigned(FX86Flags)) then FX86Flags.Free; + inherited; +end; + +procedure TInstructionDefinition.EndUpdate; +begin + if (FUpdateCount > 0) then + begin + Dec(FUpdateCount); + end; + if (FUpdateCount = 0) then + begin + if (FDoUpdatePosition) then + begin + UpdatePosition; + FDoUpdatePosition := false; + end; + if (FDoUpdateValues) then + begin + UpdateValues; + FDoUpdateValues := false; + end; + end; +end; + +function TInstructionDefinition.Equals(const Value: TInstructionDefinition): Boolean; +begin + // Comment is excluded from the equality check + Result := + (Value.FMnemonic = FMnemonic) and (Value.FEncoding = FEncoding) and + (Value.FOpcodeMap = FOpcodeMap) and (Value.FOpcode = FOpcode) and + (Value.FExtensions.Equals(FExtensions)) and (Value.FCPUID.Equals(FCPUID)) and + (Value.FOperands.Equals(FOperands)) and (Value.FFlags = FFlags) and + (Value.FImplicitRead.Equals(FImplicitRead)) and + (Value.FImplicitWrite.Equals(FImplicitWrite)) and (Value.FX86Flags.Equals(FX86Flags)); +end; + +function TInstructionDefinition.GetConflictState: Boolean; +begin + Result := (FConflicts <> []); +end; + +procedure TInstructionDefinition.LoadFromJSON(JSON: PJSONVariantData); +var + I: Integer; + A: PJSONVariantData; + F: TInstructionDefinitionFlag; + Flags: TInstructionDefinitionFlags; +begin + BeginUpdate; + try + if (VarIsClear(JSON^.Value['mnemonic']) or (JSON^.Value['mnemonic'] = '')) then + begin + raise Exception.Create('The "mnemonic" field can not be empty.'); + end; + SetMnemonic(JSON^.Value['mnemonic']); + I := TJSONEnumHelper.ReadEnumValueFromString(JSON, 'encoding', SInstructionEncoding); + SetEncoding(TInstructionEncoding(I)); + I := TJSONEnumHelper.ReadEnumValueFromString(JSON, 'map', SOpcodeMap); + SetOpcodeMap(TOpcodeMap(I)); + if (VarIsClear(JSON^.Value['opcode']) or + (not TryStrToInt('$' + JSON^.Value['opcode'], I))) or (I < 0) or (I >= 256) then + begin + raise Exception.Create('The "opcode" field does not contain a valid hexadecimal byte value.'); + end; + SetOpcode(I); + + FEVEXCD8Scale := JSON^.Value['cd8scale']; + + FExtensions.LoadFromJSON(JSON, 'extensions'); + FCPUID.LoadFromJSON(JSON, 'cpuid'); + FOperands.LoadFromJSON(JSON, 'operands'); + FImplicitRead.LoadFromJSON(JSON, 'implicit_read'); + FImplicitWrite.LoadFromJSON(JSON, 'implicit_write'); + A := JSON.Data('flags'); + if (Assigned(A)) then + begin + if (A^.Kind <> jvArray) then + begin + raise Exception.Create('The "flags" field is not a valid JSON array.'); + end; + Flags := []; + for I := 0 to A^.Count - 1 do + begin + for F := Low(SInstructionDefinitionFlag) to High(SInstructionDefinitionFlag) do + begin + if (LowerCase(A^.Item[I]) = SInstructionDefinitionFlag[F]) then + begin + Flags := Flags + [F]; + Break; + end; + end; + end; + SetFlags(Flags); + end; + FX86Flags.LoadFromJSON(JSON, 'x86flags'); + FComment := JSON^.Value['comment']; + finally + EndUpdate; + end; +end; + +procedure TInstructionDefinition.SaveToJSON(JSON: PJSONVariantData); +var + A: TJSONVariantData; + F: TInstructionDefinitionFlag; +begin + JSON^.AddNameValue('mnemonic', FMnemonic); + JSON^.AddNameValue('opcode', LowerCase(IntToHex(FOpcode, 2))); + if (FEncoding <> ieDefault) then JSON^.AddNameValue('encoding', SInstructionEncoding[FEncoding]); + if (FOpcodeMap <> omDefault) then JSON^.AddNameValue('map', SOpcodeMap[FOpcodeMap]); + FExtensions.SaveToJSON(JSON, 'extensions'); + FCPUID.SaveToJSON(JSON, 'cpuid'); + FOperands.SaveToJSON(JSON, 'operands'); + FImplicitRead.SaveToJSON(JSON, 'implicit_read'); + FImplicitWrite.SaveToJSON(JSON, 'implicit_write'); + A.Init; + for F in FFlags do + begin + A.AddValue(SInstructionDefinitionFlag[F]); + end; + if (A.Count > 0) then + begin + JSON^.AddNameValue('flags', Variant(A)); + end; + FX86Flags.SaveToJSON(JSON, 'x86flags'); + if (FComment <> '') then + begin + JSON^.AddNameValue('comment', FComment); + end; + JSON^.AddNameValue('cd8scale', FEVEXCD8Scale); +end; + +procedure TInstructionDefinition.SetComment(const Value: String); +begin + if (FComment <> Value) then + begin + FComment := Value; + UpdateValues; + end; +end; + +procedure TInstructionDefinition.SetEncoding(const Value: TInstructionEncoding); +begin + if (FEncoding <> Value) then + begin + // TODO: Check exception cases + case Value of + ieDefault, + ieVEX, + ieEVEX: + begin + if (not (FOpcodeMap in [omDefault, om0F, om0F38, om0F3A])) then FOpcodeMap := omDefault; + end; + ie3DNow: + begin + if (FOpcodeMap <> om0F) then FOpcodeMap := om0F; + end; + ieXOP: + begin + if (not (FOpcodeMap in [omXOP8, omXOP9, omXOPA])) then FOpcodeMap := omXOP8; + end; + end; + FEncoding := Value; + UpdatePosition; + end; +end; + +procedure TInstructionDefinition.SetFlags(const Value: TInstructionDefinitionFlags); +begin + if (FFlags <> Value) then + begin + FFlags := Value; + UpdateValues; + end; +end; + +procedure TInstructionDefinition.SetMnemonic(const Value: String); +begin + if (Value = '') then + begin + raise Exception.Create('Mnemonic can not be empty.'); + end; + if (FMnemonic <> Value) then + begin + FMnemonic := LowerCase(Value); + UpdateValues; + end; +end; + +procedure TInstructionDefinition.SetOpcode(const Value: TOpcodeByte); +begin + if (FOpcode <> Value) then + begin + FOpcode := Value; + UpdatePosition; + end; +end; + +procedure TInstructionDefinition.SetOpcodeMap(const Value: TOpcodeMap); +var + E: Boolean; +begin + if (FOpcodeMap <> Value) then + begin + E := false; + case FEncoding of + ieDefault, + ieVEX, + ieEVEX : E := (Value in [omXOP8, omXOP9, omXOPA]); + ie3DNow : E := (Value <> om0F); + ieXOP : E := (Value in [omDefault, om0F, om0F38, om0F3A]); + end; + if (E) then + begin + raise Exception.Create('The current instruction encoding does not support this opcode map.'); + end; + FOpcodeMap := Value; + UpdatePosition; + end; +end; + +procedure TInstructionDefinition.SetParent(Parent: TDefinitionContainer); +begin + // This method should ONLY be called by TInstructionDefinition.Create, + // TInstructionFilter.InsertDefinition and TInstructionFilter.RemoveDefinition + if (Assigned(FParent)) then + begin + if (HasConflicts) then + begin + FParent.DecInheritedConflictCount; + end; + FEditor.DefinitionRemoved(Self); + end; + FParent := Parent; + if (Assigned(Parent)) then + begin + if (HasConflicts) then + begin + FParent.IncInheritedConflictCount; + end; + FEditor.DefinitionInserted(Self); + end; +end; + +procedure TInstructionDefinition.Update; +begin + UpdatePosition; + UpdateValues; +end; + +procedure TInstructionDefinition.UpdateConflictFlags; +var + Conflicts: TInstructionDefinitionConflicts; +begin + Conflicts := []; + if (ifForceConflict in FFlags) then + begin + Include(Conflicts, idcForcedConflict); + end; + if (FOperands.HasConflicts) then + begin + Include(Conflicts, idcOperands); + end; + // TODO: Check for X86Flag conflicts + // [ ] EFLAGS in ImplicitRead / ImplicitWrite required or forbidden + // TODO: Check for more conflicts + if (FConflicts <> Conflicts) then + begin + if (Assigned(FParent)) then + begin + if (FConflicts = []) and (Conflicts <> []) then + begin + FParent.IncInheritedConflictCount; + end else if (FConflicts <> []) and (Conflicts = []) then + begin + FParent.DecInheritedConflictCount; + end; + end; + FConflicts := Conflicts; + end; +end; + +procedure TInstructionDefinition.UpdatePosition; +begin + UpdateValues; + if (FUpdateCount > 0) then + begin + FDoUpdatePosition := true; + end else + begin + FEditor.InsertDefinition(Self); + end; +end; + +procedure TInstructionDefinition.UpdateValues; +begin + if (FUpdateCount > 0) then + begin + FDoUpdateValues := true; + end else + begin + UpdateConflictFlags; + FEditor.DefinitionChanged(Self); + end; +end; +{$ENDREGION} + +{$REGION 'Class: TInstructionFilter'} +procedure TInstructionFilter.Changed; +begin + // TODO: Implement BeginUpdate, EndUpdate to reduce Changed calls + FEditor.FilterChanged(Self); +end; + +constructor TInstructionFilter.Create(Editor: TInstructionEditor; Parent: TInstructionFilter; + IsRootTable, IsStaticFilter: Boolean); +begin + inherited Create; + + Assert(Assigned(Editor)); + Assert((not Assigned(Parent)) or + (Assigned(Parent) and IsStaticFilter and (iffIsStaticFilter in Parent.FilterFlags)) or + (Assigned(Parent) and (not IsStaticFilter))); + + FEditor := Editor; + if (IsRootTable) then + begin + FFilterFlags := FFilterFlags + [iffIsRootTable]; + end; + if (IsStaticFilter) then + begin + FFilterFlags := FFilterFlags + [iffIsStaticFilter]; + end; + if (IsDefinitionContainer) then + begin + FFilterFlags := FFilterFlags + [iffIsDefinitionContainer]; + FDefinitions := TList.Create; + end else + begin + SetLength(FItems, GetCapacity); + end; + FEditor.FilterCreated(Self); + SetParent(Parent); +end; + +procedure TInstructionFilter.CreateFilterAtIndex(Index: Integer; + FilterClass: TInstructionFilterClass; IsRootTable, IsStaticFilter: Boolean); +begin + SetItem(Index, FilterClass.Create(FEditor, Self, IsRootTable, IsStaticFilter)); +end; + +procedure TInstructionFilter.DecInheritedConflictCount; +begin + Dec(FInheritedConflicts); + if (FInheritedConflicts = 0) then + begin + SetConflicts(FConflicts - [ifcInheritedConflict]); + if (Assigned(FParent)) then + begin + FParent.DecInheritedConflictCount; + end; + end; +end; + +destructor TInstructionFilter.Destroy; +begin + Assert((FItemCount = 0) and (FParent = nil)); + if Assigned(FDefinitions) then + begin + Assert(FDefinitions.Count = 0); + FDefinitions.Free; + end; + FEditor.FilterDestroyed(Self); + inherited; +end; + +class function TInstructionFilter.GetCapacity: Cardinal; +begin + Result := 0; +end; + +function TInstructionFilter.GetConflictState: Boolean; +begin + Result := (FConflicts <> []); +end; + +function TInstructionFilter.GetDefinition(const Index: Integer): TInstructionDefinition; +begin + Assert((Index >= 0) and (Index < FDefinitions.Count)); + Result := FDefinitions[Index]; +end; + +function TInstructionFilter.GetDefinitionCount: Integer; +begin + Result := 0; + if Assigned(FDefinitions) then + begin + Result := FDefinitions.Count; + end; +end; + +class function TInstructionFilter.GetDescription: String; +begin + Result := Self.ClassName; +end; + +class function TInstructionFilter.GetInsertPosition( + const Definition: TInstructionDefinition): Integer; +begin + Result := -1; +end; + +function TInstructionFilter.GetItem(const Index: Integer): TInstructionFilter; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := FItems[Index]; +end; + +class function TInstructionFilter.GetItemDescription(Index: Integer): String; +begin + Result := ''; +end; + +class function TInstructionFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netNotAvailable; +end; + +procedure TInstructionFilter.IncInheritedConflictCount; +begin + Inc(FInheritedConflicts); + if (FInheritedConflicts = 1) then + begin + SetConflicts(FConflicts + [ifcInheritedConflict]); + if (Assigned(FParent)) then + begin + FParent.IncInheritedConflictCount; + end; + end; +end; + +function TInstructionFilter.IndexOf(const Filter: TInstructionFilter): Integer; +var + I: Integer; +begin + Result := -1; + for I := Low(FItems) to High(FItems) do + begin + if (FItems[I] = Filter) then + begin + Result := I; + Break; + end; + end; +end; + +procedure TInstructionFilter.InsertDefinition(Definition: TInstructionDefinition); +begin + Assert(IsDefinitionContainer); + FDefinitions.Add(Definition); + Definition.SetParent(Self as TDefinitionContainer); + if (FDefinitions.Count = 2) then + begin + SetConflicts(FConflicts + [ifcDefinitionCount]); + if (Assigned(FParent)) then + begin + FParent.IncInheritedConflictCount; + end; + end; + Changed; +end; + +class function TInstructionFilter.IsDefinitionContainer: Boolean; +begin + Result := false; +end; + +procedure TInstructionFilter.RemoveDefinition(Definition: TInstructionDefinition); +begin + Assert(IsDefinitionContainer); + Assert(FDefinitions.IndexOf(Definition) >= 0); + if (FDefinitions.Count = 2) then + begin + SetConflicts(FConflicts - [ifcDefinitionCount]); + if (Assigned(FParent)) then + begin + FParent.DecInheritedConflictCount; + end; + end; + Definition.SetParent(nil); + FDefinitions.Remove(Definition); + Changed; +end; + +procedure TInstructionFilter.SetConflicts(const Value: TInstructionFilterConflicts); +begin + if (FConflicts <> Value) then + begin + FConflicts := Value; + Changed; + end; +end; + +procedure TInstructionFilter.SetItem(const Index: Integer; const Value: TInstructionFilter); +begin + Assert((Index >= 0) and (Index < Length(FItems))); + if (FItems[Index] <> Value) then + begin + if (Assigned(Value) and (not Assigned(FItems[Index]))) then + begin + Inc(FItemCount); + end else if (not Assigned(Value) and (Assigned(FItems[Index]))) then + begin + Dec(FItemCount); + end; + if (Assigned(FItems[Index])) then + begin + FItems[Index].SetParent(nil); + end; + FItems[Index] := Value; + if (Assigned(Value)) then + begin + FItems[Index].SetParent(Self); + end; + // Update neutral element conflict + if (GetNeutralElementType in [netPlaceholder]) then + begin + if (Assigned(FItems[0])) and (FItemCount > 1) then + begin + if (not (ifcNeutralElement in FConflicts)) then + begin + SetConflicts(FConflicts + [ifcNeutralElement]); + if (Assigned(FParent)) then + begin + FParent.IncInheritedConflictCount; + end; + end; + end else + begin + if (ifcNeutralElement in FConflicts) then + begin + SetConflicts(FConflicts - [ifcNeutralElement]); + if (Assigned(FParent)) then + begin + FParent.DecInheritedConflictCount; + end; + end; + end; + end; + Changed; + end; +end; + +procedure TInstructionFilter.SetParent(Parent: TInstructionFilter); +begin + Assert((not Assigned(Parent)) or + (Assigned(Parent) and (iffIsStaticFilter in FFilterFlags) and + (iffIsStaticFilter in Parent.FilterFlags)) or (Assigned(Parent) and + (not (iffIsStaticFilter in FFilterFlags)))); + if (FParent <> Parent) then + begin + if (Assigned(FParent)) then + begin + FEditor.FilterRemoved(Self); + if (HasConflicts) then + begin + FParent.DecInheritedConflictCount; + end; + end; + FParent := Parent; + if (Assigned(Parent)) then + begin + FEditor.FilterInserted(Self); + if (HasConflicts) then + begin + Parent.IncInheritedConflictCount; + end; + end; + Changed; + end; +end; +{$ENDREGION} + +{$REGION 'Class: TDefinitionContainer'} +class function TDefinitionContainer.IsDefinitionContainer: Boolean; +begin + Result := true; +end; +{$ENDREGION} + +{$REGION 'Class: TInstructionEditor'} +procedure TInstructionEditor.BeginUpdate; +begin + Inc(FUpdateCount); + if (FUpdateCount = 1) and Assigned(FOnBeginUpdate) then + begin + FOnBeginUpdate(Self); + end; +end; + +constructor TInstructionEditor.Create; +begin + inherited Create; + FDefinitions := TList.Create; +end; + +class constructor TInstructionEditor.Create; +begin + // Default filter order + SetLength(FilterOrderDef, 8); + FilterOrderDef[ 0] := TModrmModFilter; + FilterOrderDef[ 1] := TModrmRegFilter; + FilterOrderDef[ 2] := TModrmRmFilter; + FilterOrderDef[ 3] := TRexWFilter; + FilterOrderDef[ 4] := TOperandSizeFilter; + FilterOrderDef[ 5] := TAddressSizeFilter; + FilterOrderDef[ 6] := TMandatoryPrefixFilter; + FilterOrderDef[ 7] := TModeFilter; + // Specialized filter order for XOP instruction encoding + SetLength(FilterOrderXOP, 8); + FilterOrderXOP[ 0] := TModrmModFilter; + FilterOrderXOP[ 1] := TModrmRegFilter; + FilterOrderXOP[ 2] := TModrmRmFilter; + FilterOrderXOP[ 3] := TRexWFilter; + FilterOrderXOP[ 4] := TOperandSizeFilter; + FilterOrderXOP[ 5] := TAddressSizeFilter; + FilterOrderXOP[ 6] := TModeFilter; + FilterOrderXOP[ 7] := TVexLFilter; + // Specialized filter order for VEX instruction encoding + SetLength(FilterOrderVEX, 9); + FilterOrderVEX[ 0] := TOpcodeFilter; + FilterOrderVEX[ 1] := TModrmModFilter; + FilterOrderVEX[ 2] := TModrmRegFilter; + FilterOrderVEX[ 3] := TModrmRmFilter; + FilterOrderVEX[ 4] := TRexWFilter; + FilterOrderVEX[ 5] := TOperandSizeFilter; + FilterOrderVEX[ 6] := TAddressSizeFilter; + FilterOrderVEX[ 7] := TModeFilter; + FilterOrderVEX[ 8] := TVexLFilter; + // Specialized filter order for EVEX instruction encoding + SetLength(FilterOrderEVEX, 11); + FilterOrderEVEX[ 0] := TOpcodeFilter; + FilterOrderEVEX[ 1] := TModrmModFilter; + FilterOrderEVEX[ 2] := TModrmRegFilter; + FilterOrderEVEX[ 3] := TModrmRmFilter; + FilterOrderEVEX[ 4] := TRexWFilter; + FilterOrderEVEX[ 5] := TOperandSizeFilter; + FilterOrderEVEX[ 6] := TAddressSizeFilter; + FilterOrderEVEX[ 7] := TModeFilter; + FilterOrderEVEX[ 8] := TEvexBFilter; + FilterOrderEVEX[ 9] := TVexLFilter; + FilterOrderEVEX[10] := TEvexL2Filter; +end; + +function TInstructionEditor.CreateDefinition(const Mnemonic: String): TInstructionDefinition; +begin + Result := TInstructionDefinition.Create(Self, Mnemonic); +end; + +procedure TInstructionEditor.DefinitionChanged(Definition: TInstructionDefinition); +begin + if Assigned(FOnDefinitionChanged) then + begin + FOnDefinitionChanged(Self, Definition); + end; +end; + +procedure TInstructionEditor.DefinitionInserted(Definition: TInstructionDefinition); +begin + if Assigned(FOnDefinitionInserted) then + begin + FOnDefinitionInserted(Self, Definition); + end; +end; + +procedure TInstructionEditor.DefinitionRemoved(Definition: TInstructionDefinition); +begin + if Assigned(FOnDefinitionRemoved) then + begin + FOnDefinitionRemoved(Self, Definition); + end; +end; + +destructor TInstructionEditor.Destroy; + +procedure DestroyChildFilters(Filter: TInstructionFilter); +var + I: Integer; + F: TInstructionFilter; +begin + Assert(iffIsStaticFilter in Filter.FilterFlags); + if (Filter.ItemCount > 0) then + begin + for I := 0 to Filter.Capacity - 1 do + begin + if (Assigned(Filter.Items[I])) then + begin + DestroyChildFilters(Filter.Items[I]); + F := Filter.Items[I]; + Filter.SetItem(I, nil); + F.Free; + end; + end; + end; +end; + +var + I: Integer; +begin + BeginUpdate; + try + if (Assigned(FDefinitions)) then + begin + FPreventDefinitionRemoval := true; + for I := FDefinitions.Count - 1 downto 0 do + begin + FDefinitions[I].Free; + end; + FDefinitions.Free; + end; + if Assigned(FRootTable) then + begin + DestroyChildFilters(FRootTable); + FRootTable.Free; + end; + finally + EndUpdate; + end; + inherited; +end; + +procedure TInstructionEditor.EndUpdate; +begin + if (FUpdateCount > 0) then + begin + Dec(FUpdateCount); + end; + if (FUpdateCount = 0) then + begin + if Assigned(FOnEndUpdate) then + begin + FOnEndUpdate(Self); + end; + end; +end; + +procedure TInstructionEditor.FilterChanged(Filter: TInstructionFilter); +begin + if Assigned(FOnFilterChanged) then + begin + FOnFilterChanged(Self, Filter); + end; +end; + +procedure TInstructionEditor.FilterCreated(Filter: TInstructionFilter); +begin + if Assigned(FOnFilterCreated) then + begin + FOnFilterCreated(Self, Filter); + end; +end; + +procedure TInstructionEditor.FilterDestroyed(Filter: TInstructionFilter); +begin + if Assigned(FOnFilterDestroyed) then + begin + FOnFilterDestroyed(Self, Filter); + end; +end; + +procedure TInstructionEditor.FilterInserted(Filter: TInstructionFilter); +begin + if (not Filter.IsDefinitionContainer) then Inc(FFilterCount); + if Assigned(FOnFilterInserted) then + begin + FOnFilterInserted(Self, Filter); + end; +end; + +procedure TInstructionEditor.FilterRemoved(Filter: TInstructionFilter); +begin + if (not Filter.IsDefinitionContainer) then Dec(FFilterCount); + if Assigned(FOnFilterRemoved) then + begin + FOnFilterRemoved(Self, Filter); + end; +end; + +function TInstructionEditor.GetDefinition(const Index: Integer): TInstructionDefinition; +begin + Assert((Index >= 0) and (Index < FDefinitions.Count)); + Result := FDefinitions[Index]; +end; + +function TInstructionEditor.GetDefinitionCount: Integer; +begin + Result := FDefinitions.Count; +end; + +function TInstructionEditor.GetDefinitionTopLevelFilter( + Definition: TInstructionDefinition): TInstructionFilter; +begin + Result := nil; + case Definition.Encoding of + ieDefault: + begin + case Definition.OpcodeMap of + omDefault: + Result := FRootTable; + om0F: + Result := FRootTable.Items[$0F]; + om0F38: + Result := FRootTable.Items[$0F].Items[$38]; + om0F3A: + Result := FRootTable.Items[$0F].Items[$3A]; + omXOP8, + omXOP9, + omXOPA: + Assert(false); + end; + end; + ie3DNow: + Result := FRootTable.Items[$0F].Items[$0F].Items[$01]; + ieXOP: + begin + case Definition.OpcodeMap of + omDefault, + om0F, + om0F38, + om0F3A: Assert(false); + omXOP8: + Result := FRootTable.Items[$8F].Items[$02].Items[$01]; + omXOP9: + Result := FRootTable.Items[$8F].Items[$02].Items[$02]; + omXOPA: + Result := FRootTable.Items[$8F].Items[$02].Items[$03]; + end; + end; + ieVEX: + Result := FRootTable.Items[$C4].Items[$03]; + ieEVEX: + Result := FRootTable.Items[$62].Items[$04]; + end; + Assert(Assigned(Result)); +end; + +class function TInstructionEditor.GetFilterList( + Encoding: TInstructionEncoding): PInstructionFilterList; +begin + Result := @FilterOrderDef; + case Encoding of + ieXOP: + Result := @FilterOrderXOP; + ieVEX: + Result := @FilterOrderVEX; + ieEVEX: + Result := @FilterOrderEVEX; + end; +end; + +procedure TInstructionEditor.InsertDefinition(Definition: TInstructionDefinition); +var + F, T: TInstructionFilter; + I, Index: Integer; + FilterList: PInstructionFilterList; + IsRequiredFilter: Boolean; +begin + BeginUpdate; + try + // Remove the definition from its old position + RemoveDefinition(Definition); + + // Skip all static tables. This code assumes that the parent of a static-table is always + // another static table. + // There is no need to create a static table as child of a non-static one at the moment. + F := GetDefinitionToplevelFilter(Definition); + Index := F.GetInsertPosition(Definition); + while (Assigned(F.Items[Index])) and (iffIsStaticFilter in F.Items[Index].FilterFlags) do + begin + F := F.Items[Index]; + Index := F.GetInsertPosition(Definition); + end; + + // Create required filters + FilterList := GetFilterList(Definition.Encoding); + for I := Low(FilterList^) to High(FilterList^) do + begin + // Check if the current definition requires this filter + IsRequiredFilter := false; + case FilterList^[I].GetNeutralElementType of + netNotAvailable: + IsRequiredFilter := (FilterList^[I].GetInsertPosition(Definition) >= 0); + netPlaceholder, + netValue: + IsRequiredFilter := (FilterList^[I].GetInsertPosition(Definition) > 0); + end; + + Index := F.GetInsertPosition(Definition); + + // We have to enforce this filter, if a definition in the target-slot already requires the + // same filter type + if (not IsRequiredFilter) and (FilterList^[I].GetNeutralElementType <> netNotAvailable) and + (F.Items[Index] is FilterList^[I]) then + begin + IsRequiredFilter := true; + end; + + if (IsRequiredFilter) then + begin + // If the target slot is not occupied, just go ahead and create the new filter + if (not Assigned(F.Items[Index])) then + begin + F.CreateFilterAtIndex(Index, FilterList^[I], false, false); + end; + // If the target slot is occupied by a different filter type, we need to save the old + // filter and insert it into our new one + if (F.Items[Index] is FilterList^[I]) then + begin + F := F.Items[Index]; + end else + begin + T := F.Items[Index]; + F.CreateFilterAtIndex(Index, FilterList^[I], false, false); + F := F.Items[Index]; + F.SetItem(0, T); + end; + end; + end; + + // Create a definition-container and actually insert the definition + Index := F.GetInsertPosition(Definition); + if (not Assigned(F.Items[Index])) then + begin + F.CreateFilterAtIndex(Index, TDefinitionContainer, false, false); + end; + F.Items[Index].InsertDefinition(Definition); + finally + EndUpdate; + end; +end; + +procedure TInstructionEditor.LoadFromFile(const Filename: String); +var + List: TStringList; + JSON: TJSONVariantData; +begin + List := TStringList.Create; + try + List.LoadFromFile(Filename); + JSON.Init; + if (not JSON.FromJSON(List.Text)) or (JSON.Kind <> jvObject) then + begin + raise Exception.Create('Could not parse JSON file.'); + end; + LoadFromJSON(@JSON); + finally + List.Free; + end; +end; + +procedure TInstructionEditor.LoadFromJSON(JSON: PJSONVariantData); +var + JSONDefinitions, + JSONDefinition: PJSONVariantData; + I: Integer; + Definition: TInstructionDefinition; +begin + BeginUpdate; + try + Reset; + try + if (JSON^.Kind <> jvObject) then + begin + raise Exception.Create('Invalid JSON object.'); + end; + JSONDefinitions := JSON^.Data('definitions'); + if ((not Assigned(JSONDefinitions)) or (JSONDefinitions^.Kind <> jvArray)) then + begin + raise Exception.Create( + 'The JSON object does not contain the required "definitions" array.'); + end; + if (Assigned(FOnWorkStart)) then + begin + FOnWorkStart(Self, 0, JSONDefinitions^.Count); + end; + for I := 0 to JSONDefinitions^.Count - 1 do + begin + JSONDefinition := JSONVariantDataSafe(JSONDefinitions^.Item[I], jvObject); + if (not Assigned(JSONDefinition)) then + begin + raise Exception.CreateFmt( + 'The definition item #%d is not a valid JSON object.', [I + 1]); + end; + // RegisterDefinition and InsertDefinition are indirectly called + Definition := CreateDefinition('unnamed'); + Definition.BeginUpdate; + try + try + Definition.UpdatePosition; + Definition.LoadFromJSON(JSONDefinition); + except + on E: Exception do + begin + raise Exception.CreateFmt( + 'Error while parsing definition #%d: "%s"', [I + 1, E.Message]); + end; + end; + finally + Definition.EndUpdate; + end; + if (Assigned(FOnWork)) then + begin + FOnWork(Self, I + 1); + end; + end; + if (Assigned(FOnWorkEnd)) then + begin + FOnWorkEnd(Self); + end; + except + Reset; + raise; + end; + finally + EndUpdate; + end; +end; + +procedure TInstructionEditor.RegisterDefinition(Definition: TInstructionDefinition); +begin + // This method is automatically called by TInstructionDefinition.Create + Assert(not FDefinitions.Contains(Definition)); + FDefinitions.Add(Definition); + if Assigned(FOnDefinitionCreated) then + begin + FOnDefinitionCreated(Self, Definition); + end; +end; + +procedure TInstructionEditor.RemoveDefinition(Definition: TInstructionDefinition); +var + F, P, T: TInstructionFilter; + I: Integer; + DoRemove: Boolean; +begin + if (not Assigned(Definition.Parent)) then + begin + Exit; + end; + BeginUpdate; + try + F := Definition.Parent; + F.RemoveDefinition(Definition); + if (F.DefinitionCount > 0) then + begin + Exit; + end; + // Remove empty filter tables + DoRemove := true; + while (DoRemove and Assigned(F) and (not (iffIsRootTable in F.FilterFlags))) do + begin + if (F.IsDefinitionContainer) then + begin + DoRemove := (F.DefinitionCount = 0); + end else + begin + DoRemove := (not (iffIsStaticFilter in F.FilterFlags)) and + ((F.ItemCount = 0) or ((F.NeutralElementType <> netNotAvailable) and + (F.ItemCount = 1) and (Assigned(F.Items[0])))); + end; + if (DoRemove) then + begin + Assert(Assigned(F.Parent)); + P := F.Parent; + I := P.IndexOf(F); + if (not (F.IsDefinitionContainer)) and (Assigned(F.Items[0])) then + begin + T := F.Items[0]; + F.SetItem(0, nil); + P.SetItem(I, T); + end else + begin + P.SetItem(I, nil); + end; + F.Free; + F := P; + end; + end; + finally + EndUpdate; + end; +end; + +procedure TInstructionEditor.Reset; +var + I: Integer; +begin + BeginUpdate; + try + FPreventDefinitionRemoval := true; + for I := FDefinitions.Count - 1 downto 0 do + begin + FDefinitions[I].Free; + end; + FPreventDefinitionRemoval := false; + FDefinitions.Clear; + if (not Assigned(FRootTable)) then + begin + FFilterCount := 1; + // 1, 2 and 3 Byte Opcode Tables + FRootTable := TOpcodeFilter.Create(Self, nil, true, true); + FRootTable.CreateFilterAtIndex($0F, TOpcodeFilter, false, true); + FRootTable.Items[$0F].CreateFilterAtIndex($38, TOpcodeFilter, false, true); + FRootTable.Items[$0F].CreateFilterAtIndex($3A, TOpcodeFilter, false, true); + // 3DNow Table + FRootTable.Items[$0F].CreateFilterAtIndex($0F, TEncodingFilter, false, true); + FRootTable.Items[$0F].Items[$0F].CreateFilterAtIndex($01, TOpcodeFilter, false, true); + // 3 Byte VEX Table + FRootTable.CreateFilterAtIndex($C4, TEncodingFilter, false, true); + FRootTable.Items[$C4].CreateFilterAtIndex($03, TVEXMapFilter, false, true); + // 2 Byte VEX Table (we copy the 3 byte VEX table later) + FRootTable.CreateFilterAtIndex($C5, TEncodingFilter, false, true); + FRootTable.Items[$C5].CreateFilterAtIndex($03, TVEXMapFilter, false, true); + // XOP Table + FRootTable.CreateFilterAtIndex($8F, TEncodingFilter, false, true); + FRootTable.Items[$8F].CreateFilterAtIndex($02, TXOPMapFilter, false, true); + for I := 1 to FRootTable.Items[$8F].Items[$02].Capacity - 1 do + begin + FRootTable.Items[$8F].Items[$02].CreateFilterAtIndex(I, TOpcodeFilter, false, true); + end; + // EVEX Table + FRootTable.CreateFilterAtIndex($62, TEncodingFilter, false, true); + FRootTable.Items[$62].CreateFilterAtIndex($04, TVEXMapFilter, false, true); + end; + finally + EndUpdate; + end; +end; + +procedure TInstructionEditor.SaveToFile(const Filename: String); +var + JSON: TJSONVariantData; + List: TStringList; +begin + JSON.Init; + SaveToJSON(@JSON); + List := TStringList.Create; + try + List.Text := TJSONHelper.JSONToString(@JSON); + List.SaveToFile(FileName); + finally + List.Free; + end; +end; + +procedure TInstructionEditor.SaveToJSON(JSON: PJSONVariantData); +var + Comparison: TComparison; + I: Integer; + JSONDefinitionList, JSONDefinition: TJSONVariantData; +begin + // Sort definitions by mnemonic + Comparison := + function(const Left, Right: TInstructionDefinition): Integer + begin + Result := CompareStr(Left.Mnemonic, Right.Mnemonic); + end; + FDefinitions.Sort(TComparer.Construct(Comparison)); + // Save to JSON + if (Assigned(FOnWorkStart)) then + begin + FOnWorkStart(Self, 0, FDefinitions.Count); + end; + JSONDefinitionList.Init; + for I := 0 to FDefinitions.Count - 1 do + begin + JSONDefinition.Init; + FDefinitions[I].SaveToJSON(@JSONDefinition); + JSONDefinitionList.AddValue(Variant(JSONDefinition)); + if (Assigned(FOnWork)) then + begin + FOnWork(Self, I + 1); + end; + end; + JSON^.AddNameValue('definitions', Variant(JSONDefinitionList)); + if (Assigned(FOnWorkEnd)) then + begin + FOnWorkEnd(Self); + end; +end; + +procedure TInstructionEditor.UnregisterDefinition(Definition: TInstructionDefinition); +begin + // This method is automatically called by TInstructionDefinition.Destroy + Assert(FDefinitions.Contains(Definition)); + if Assigned(FOnDefinitionDestroyed) then + begin + FOnDefinitionDestroyed(Self, Definition); + end; + if (not FPreventDefinitionRemoval) then + begin + FDefinitions.Remove(Definition); + end; +end; +{$ENDREGION} + +{$REGION 'Const: Constants used by TTableGenerator'} +const + MNEMONIC_ALIASES: array[0..0] of String = ( + 'nop' + ); + FILENAME_INSTRUCTIONTABLE = 'InstructionTable.inc'; + FILENAME_MNEMONICENUM = 'Mnemonics.inc'; + FILENAME_MNEMONICSTRINGS = 'MnemonicStrings.inc'; + FILENAME_INSTRUCTIONDEFINITIONS = 'InstructionDefinitions.inc'; + SIZEOF_INSTRUCTIONTABLENODE = 3; + SIZEOF_INSTRUCTIONDEFINITION = 10; + TYPEOF_INSTRUCTIONTABLENODE = 'ZydisInstructionTableNode'; + TYPEOF_INSTRUCTIONOPERANDS = 'ZydisInstructionOperands'; + TYPEOF_INSTRUCTIONDEFINITION = 'ZydisInstructionDefinition'; + INSTRUCTIONTABLENODE_INVALID = 'ZYDIS_INVALID'; + INSTRUCTIONTABLENODE_FILTER = 'ZYDIS_FILTER'; + INSTRUCTIONTABLENODE_DEFINITION = 'ZYDIS_DEFINITION'; + PREFIX_FILTERARRAY = 'filter'; + PREFIX_FILTERTYPE = 'ZYDIS_NODETYPE_FILTER_'; + PREFIX_MNEMONIC = 'ZYDIS_MNEMONIC_'; + INSTRUCTIONDEFINITION_DEFINITION = 'ZYDIS_MAKE_DEFINITION'; + INSTRUCTIONDEFINITION_OPERAND = 'ZYDIS_MAKE_OPERAND'; + PREFIX_OPERAND_TYPE = 'ZYDIS_SEM_OPERAND_TYPE_'; + PREFIX_OPERAND_ENCODING = 'ZYDIS_OPERAND_ENCODING_'; + PREFIX_OPERAND_ACCESSMODE = 'ZYDIS_OPERAND_ACCESS_'; + ARRAYNAME_INSTRUCTIONOPERANDS = 'instructionOperands'; + ARRAYNAME_INSTRUCTIONDEFINITIONS = 'instructionDefinitions'; +{$ENDREGION} + +{$REGION 'Class: TTableGenerator'} +constructor TTableGenerator.Create; +begin + inherited Create; + +end; + +procedure TTableGenerator.CreateEntityLists(Editor: TInstructionEditor; + var FilterList: TIndexedFilterList; var DefinitionList: TIndexedDefinitionList; + var MnemonicList: TMnemonicList); + +var + IndexDict: TDictionary; + +procedure CreateChildIndizes(var Root: TIndexedFilterItem); +var + I, J: Integer; +begin + SetLength(Root.Items, Root.Filter.Capacity); + FillChar(Root.Items[0], Length(Root.Items) * SizeOf(Root.Items[0]), #0); + for I := 0 to Root.Filter.Capacity - 1 do + begin + Root.Items[I].Id := -1; + Root.Items[I].Filter := Root.Filter.Items[I]; + if (Assigned(Root.Items[I].Filter)) then + begin + if (not IndexDict.ContainsKey(TInstructionFilterClass(Root.Filter.Items[I].ClassType))) then + begin + Root.Items[I].Id := 0; + IndexDict.Add(TInstructionFilterClass(Root.Filter.Items[I].ClassType), 1); + end else + begin + Root.Items[I].Id := IndexDict[TInstructionFilterClass(Root.Filter.Items[I].ClassType)]; + IndexDict[TInstructionFilterClass(Root.Filter.Items[I].ClassType)] := Root.Items[I].Id + 1; + end; + + if (Root.Items[I].Filter.IsDefinitionContainer) then + begin + // Fix mnemonic index + for J := Low(DefinitionList) to High(DefinitionList) do + begin + if (DefinitionList[J].Definition.Parent = Root.Items[I].Filter) then + begin + Root.Items[I].Id := DefinitionList[J].Id; + Break; + end; + end; + end else + begin + Inc(FStatistics.FilterCount); + Inc(FStatistics.FilterSize, Root.Items[I].Filter.GetCapacity * SIZEOF_INSTRUCTIONTABLENODE); + if (Root.Items[I].Filter.NeutralElementType = netPlaceholder) then + begin + Dec(FStatistics.FilterSize, SIZEOF_INSTRUCTIONTABLENODE); + end; + Work(FStatistics.FilterCount); + end; + + CreateChildIndizes(Root.Items[I]); + end; + end; +end; + +var + ListDict: TDictionary>; + +procedure AddFiltersToListDict(const Root: TIndexedFilterItem); +var + FilterList: TList; + I: Integer; +begin + if (Root.IsRedirect) then Exit; + if (not ListDict.ContainsKey(TInstructionFilterClass(Root.Filter.ClassType))) then + begin + FilterList := TList.Create; + ListDict.Add(TInstructionFilterClass(Root.Filter.ClassType), FilterList); + end else + begin + FilterList := ListDict[TInstructionFilterClass(Root.Filter.ClassType)]; + end; + FilterList.Add(Root); + for I := Low(Root.Items) to High(Root.Items) do + begin + if (Root.Items[I].Id < 0) or (Root.Items[I].Filter is TEncodingFilter) then Continue; + AddFiltersToListDict(Root.Items[I]); + end; +end; + +var + DList: TList; + DComparison: TComparison; + MList: TList; + MComparison: TComparison; + I, J, K: Integer; + Root, Temp: TIndexedFilterItem; + A: TArray>>; +begin + // Create definition indizes and a sorted definition-list + DList := TList.Create; + try + WorkStart(woIndexingDefinitions, 0, Editor.DefinitionCount * 2); + for I := 0 to Editor.DefinitionCount - 1 do + begin + DList.Add(Editor.Definitions[I]); + Work(I + 1); + end; + DComparison := + function(const Left, Right: TInstructionDefinition): Integer + begin + Result := CompareStr(Left.Mnemonic, Right.Mnemonic); + end; + DList.Sort(TComparer.Construct(DComparison)); + SetLength(DefinitionList, DList.Count); + for I := 0 to DList.Count - 1 do + begin + DefinitionList[I].Id := I; + DefinitionList[I].Definition := DList[I]; + Work(Editor.DefinitionCount + I + 1); + end; + WorkEnd; + finally + DList.Free; + end; + FStatistics.DefinitionCount := Length(DefinitionList); + FStatistics.DefinitionSize := Length(DefinitionList) * SIZEOF_INSTRUCTIONDEFINITION; + + // Create sorted mnemonic list with all aliases + FStatistics.MnemonicSize := 0; + MList := TList.Create; + try + for I := 0 to Editor.DefinitionCount - 1 do + begin + MList.Add(Editor.Definitions[I].Mnemonic); + end; + for I := Low(MNEMONIC_ALIASES) to High(MNEMONIC_ALIASES) do + begin + MList.Add(MNEMONIC_ALIASES[I]); + end; + MComparison := + function(const Left, Right: String): Integer + begin + Result := CompareStr(Left, Right); + end; + MList.Sort(TComparer.Construct(MComparison)); + for I := MList.Count - 1 downto 1 do + begin + if (MList[I] = MList[I - 1]) then + begin + MList.Delete(I); + end; + end; + MList.Insert(0, 'invalid'); + SetLength(MnemonicList, MList.Count); + for I := 0 to MList.Count - 1 do + begin + MnemonicList[I] := MList[I]; + Inc(FStatistics.MnemonicSize, Length(MnemonicList[I])); + end; + finally + MList.Free; + end; + FStatistics.MnemonicCount := Length(MnemonicList); + + IndexDict := TDictionary.Create; + try + // Generate internal tree structure + Root.Id := 0; + Root.Filter := Editor.RootTable; + Root.IsRedirect := false; + IndexDict.Add(TOpcodeFilter, 1); + FStatistics.FilterCount := 1; + FStatistics.FilterSize := 256 * SIZEOF_INSTRUCTIONTABLENODE; + WorkStart(woIndexingFilters, 0, Editor.FilterCount - 1); + CreateChildIndizes(Root); + WorkEnd; + + // Unlink encoding filters + Root.Items[$0F].Items[$0F] := Root.Items[$0F].Items[$0F].Items[$01]; + Temp := Root.Items[$C4].Items[$03]; + Temp.Items[$00] := Root.Items[$C4].Items[$00]; + Root.Items[$C4] := Temp; + Temp := Root.Items[$C5].Items[$03]; + Temp.Items[$00] := Root.Items[$C5].Items[$00]; + Root.Items[$C5] := Temp; + Temp := Root.Items[$62].Items[$04]; + Temp.Items[$00] := Root.Items[$62].Items[$00]; + Root.Items[$62] := Temp; + Temp := Root.Items[$8F].Items[$02]; + Temp.Items[$00] := Root.Items[$8F].Items[$00]; + Root.Items[$8F] := Temp; + + // Initialize 2-byte VEX filter + Root.Items[$C5].Items[$01] := Root.Items[$C4].Items[$01]; // 0x0F + Root.Items[$C5].Items[$01].IsRedirect := true; + Root.Items[$C5].Items[$05] := Root.Items[$C4].Items[$05]; // 0x66 0x0F + Root.Items[$C5].Items[$05].IsRedirect := true; + Root.Items[$C5].Items[$09] := Root.Items[$C4].Items[$09]; // 0xF3 0x0F + Root.Items[$C5].Items[$09].IsRedirect := true; + Root.Items[$C5].Items[$0D] := Root.Items[$C4].Items[$0D]; // 0xF2 0x0F + Root.Items[$C5].Items[$0D].IsRedirect := true; + + Dec(FStatistics.FilterCount, 5); + Dec(FStatistics.FilterSize, 5 * 5 * SIZEOF_INSTRUCTIONTABLENODE); + + // Generate filter list + ListDict := + TObjectDictionary>.Create([doOwnsValues]); + try + AddFiltersToListDict(Root); + A := ListDict.ToArray; + SetLength(FilterList, Length(A)); + for I := Low(A) to High(A) do + begin + FilterList[I].Key := A[I].Key; + FilterList[I].Value := A[I].Value.ToArray; + // Clear recursive child-item arrays + for J := Low(FilterList[I].Value) to HigH(FilterList[I].Value) do + begin + for K := Low(FilterList[I].Value[J].Items) to High(FilterList[I].Value[J].Items) do + begin + SetLength(FilterList[I].Value[J].Items[K].Items, 0); + end; + end; + end; + finally + ListDict.Free; + end; + finally + IndexDict.Free; + end; +end; + +destructor TTableGenerator.Destroy; +begin + + inherited; +end; + +procedure TTableGenerator.GenerateDefinitionList(const OutputDirectory: String; + const DefinitionList: PIndexedDefinitionList); + +procedure AppendOperand(Buffer: TStringBuffer; Operand: TInstructionOperand); +var + OperandType, + OperandEncoding, + OperandAccessMode: String; +begin + OperandType := 'UNUSED'; + case Operand.OperandType of + optGPR8 : OperandType := 'GPR8'; + optGPR16 : OperandType := 'GPR16'; + optGPR32 : OperandType := 'GPR32'; + optGPR64 : OperandType := 'GPR64'; + optFPR : OperandType := 'FPR'; + optVR64 : OperandType := 'VR64'; + optVR128 : OperandType := 'VR128'; + optVR256 : OperandType := 'VR256'; + optVR512 : OperandType := 'VR512'; + optCR : OperandType := 'CR'; + optDR : OperandType := 'DR'; + optMSKR : OperandType := 'MSKR'; + optBNDR : OperandType := 'BNDR'; + optMem : OperandType := 'MEM'; + optMem8 : OperandType := 'MEM8'; + optMem16 : OperandType := 'MEM16'; + optMem32 : OperandType := 'MEM32'; + optMem64 : OperandType := 'MEM64'; + optMem80 : OperandType := 'MEM80'; + optMem128 : OperandType := 'MEM128'; + optMem256 : OperandType := 'MEM256'; + optMem512 : OperandType := 'MEM512'; + optMem32Bcst2 : OperandType := 'MEM32_BCST2'; + optMem32Bcst4 : OperandType := 'MEM32_BCST4'; + optMem32Bcst8 : OperandType := 'MEM32_BCST8'; + optMem32Bcst16: OperandType := 'MEM32_BCST16'; + optMem64Bcst2 : OperandType := 'MEM64_BCST2'; + optMem64Bcst4 : OperandType := 'MEM64_BCST4'; + optMem64Bcst8 : OperandType := 'MEM64_BCST8'; + optMem64Bcst16: OperandType := 'MEM64_BCST16'; + optMem112 : OperandType := 'MEM112'; + optMem224 : OperandType := 'MEM224'; + optImm8 : OperandType := 'IMM8'; + optImm16 : OperandType := 'IMM16'; + optImm32 : OperandType := 'IMM32'; + optImm64 : OperandType := 'IMM64'; + optImm8U : OperandType := 'IMM8U'; + optRel8 : OperandType := 'REL8'; + optRel16 : OperandType := 'REL16'; + optRel32 : OperandType := 'REL32'; + optRel64 : OperandType := 'REL64'; + optPtr1616 : OperandType := 'PTR1616'; + optPtr1632 : OperandType := 'PTR1632'; + optPtr1664 : OperandType := 'PTR1664'; + optMoffs16 : OperandType := 'MOFFS16'; + optMoffs32 : OperandType := 'MOFFS32'; + optMoffs64 : OperandType := 'MOFFS64'; + optSrcIndex8 : OperandType := 'SRCIDX8'; + optSrcIndex16 : OperandType := 'SRCIDX16'; + optSrcIndex32 : OperandType := 'SRCIDX32'; + optSrcIndex64 : OperandType := 'SRCIDX64'; + optDstIndex8 : OperandType := 'DSTIDX8'; + optDstIndex16 : OperandType := 'DSTIDX16'; + optDstIndex32 : OperandType := 'DSTIDX32'; + optDstIndex64 : OperandType := 'DSTIDX64'; + optSREG : OperandType := 'SREG'; + optMem1616 : OperandType := 'M1616'; + optMem1632 : OperandType := 'M1632'; + optMem1664 : OperandType := 'M1664'; + optMem32VSIBX : OperandType := 'MEM32_VSIBX'; + optMem32VSIBY : OperandType := 'MEM32_VSIBY'; + optMem32VSIBZ : OperandType := 'MEM32_VSIBZ'; + optMem64VSIBX : OperandType := 'MEM64_VSIBX'; + optMem64VSIBY : OperandType := 'MEM64_VSIBY'; + optMem64VSIBZ : OperandType := 'MEM64_VSIBZ'; + optFixed1 : OperandType := 'FIXED1'; + optFixedAL : OperandType := 'AL'; + optFixedCL : OperandType := 'CL'; + optFixedAX : OperandType := 'AX'; + optFixedDX : OperandType := 'DX'; + optFixedEAX : OperandType := 'EAX'; + optFixedRAX : OperandType := 'RAX'; + optFixedES : OperandType := 'ES'; + optFixedCS : OperandType := 'CS'; + optFixedSS : OperandType := 'SS'; + optFixedDS : OperandType := 'DS'; + optFixedGS : OperandType := 'GS'; + optFixedFS : OperandType := 'FS'; + optFixedST0 : OperandType := 'ST0'; + end; + OperandEncoding := 'NONE'; + case Operand.Encoding of + opeModrmReg : OperandEncoding := 'REG'; + opeModrmRm : OperandEncoding := 'RM'; + opeModrmRmCD1 : OperandEncoding := 'RM'; + opeModrmRmCD2 : OperandEncoding := 'RM_CD2'; + opeModrmRmCD4 : OperandEncoding := 'RM_CD4'; + opeModrmRmCD8 : OperandEncoding := 'RM_CD8'; + opeModrmRmCD16: OperandEncoding := 'RM_CD16'; + opeModrmRmCD32: OperandEncoding := 'RM_CD32'; + opeModrmRmCD64: OperandEncoding := 'RM_CD64'; + opeOpcodeBits : OperandEncoding := 'OPCODE'; + opeVexVVVV : OperandEncoding := 'VVVV'; + opeEvexAAA : OperandEncoding := 'AAA'; + opeImm8 : OperandEncoding := 'IMM8'; + opeImm16 : OperandEncoding := 'IMM16'; + opeImm32 : OperandEncoding := 'IMM32'; + opeImm64 : OperandEncoding := 'IMM64'; + end; + OperandAccessMode := 'READ'; + case Operand.AccessMode of + opaWrite : OperandAccessMode := 'WRITE'; + opaReadWrite : OperandAccessMode := 'READWRITE'; + end; + Buffer.Append(Format('%s(%s%s, %s%s, %s%s)', [INSTRUCTIONDEFINITION_OPERAND, + PREFIX_OPERAND_TYPE, OperandType, PREFIX_OPERAND_ENCODING, OperandEncoding, + PREFIX_OPERAND_ACCESSMODE, OperandAccessMode])); +end; + +var + Buffer: TStringBuffer; + StringList: TStringList; + I, J: Integer; + + S, T, U: String; + + Operands: TList; + B: Boolean; +begin + Operands := TList.Create; + try + for I := Low(DefinitionList^) to High(DefinitionList^) do + begin + B := false; + for J := 0 to Operands.Count - 1 do + begin + if (Operands[J].Equals(DefinitionList^[I].Definition.Operands)) then + begin + B := true; + Break; + end; + end; + if (not B) then + begin + Operands.Add(DefinitionList^[I].Definition.Operands); + end; + end; + + Buffer := TStringBuffer.Create; + try + Buffer.AppendLn(Format('const %s %s[] =', [ + TYPEOF_INSTRUCTIONOPERANDS, ARRAYNAME_INSTRUCTIONOPERANDS])); + Buffer.AppendLn('{'); + for I := 0 to Operands.Count - 1 do + begin + Buffer.Append(Format(' /*%.4x*/ { ', [I])); + for J := 0 to 3 do + begin + AppendOperand(Buffer, Operands[I].GetOperandById(J)); + if (J <> 3) then + begin + Buffer.Append(', '); + end; + end; + if (I <> (Operands.Count - 1)) then + begin + Buffer.AppendLn(' },'); + end else + begin + Buffer.AppendLn(' }'); + end; + end; + Buffer.AppendLn('};'); + Buffer.AppendLn(''); + + Buffer.AppendLn(Format('const %s %s[] =', [ + TYPEOF_INSTRUCTIONDEFINITION, ARRAYNAME_INSTRUCTIONDEFINITIONS])); + Buffer.AppendLn('{'); + WorkStart(woGeneratingDefinitionFiles, 0, Length(DefinitionList^)); + for I := Low(DefinitionList^) to High(DefinitionList^) do + begin + Buffer.Append(Format(' /*%.4x*/ ', [I])); + //Buffer.Append(Format('{ %s%s, { ', [ + Buffer.Append(Format('ZYDIS_MAKE_DEFINITION(%s%s, ', [ + PREFIX_MNEMONIC, AnsiUpperCase(DefinitionList^[I].Definition.Mnemonic)])); + {for J := 0 to 3 do + begin + AppendOperand(Buffer, DefinitionList^[I].Definition.Operands.GetOperandById(J)); + if (J <> 3) then + begin + Buffer.Append(', '); + end; + end;} + + for J := 0 to Operands.Count - 1 do + begin + if (Operands[J].Equals(DefinitionList^[I].Definition.Operands)) then + begin + Buffer.Append(Format('0x%.4x', [J])); + Break; + end; + end; + + //Buffer.Append(' }'); + + S := '0'; T := '0'; U := '0'; + if (ifAcceptsEvexAAA in DefinitionList^[I].Definition.Flags) then S := '1'; + if (ifAcceptsEvexZ in DefinitionList^[I].Definition.Flags) then T := '1'; + if (ifHasEvexBC in DefinitionList^[I].Definition.Flags) then U := '1' + else + if (ifHasEvexRC in DefinitionList^[I].Definition.Flags) then U := '2' + else + if (ifHasEvexSAE in DefinitionList^[I].Definition.Flags) then U := '3'; + + Buffer.Append(Format(', ZYDIS_MAKE_AVX512INFO(%s, %s, %s)', [U, S, T])); + + if (I <> High(DefinitionList^)) then + begin + //Buffer.AppendLn(' },'); + Buffer.AppendLn(' ),'); + end else + begin + //Buffer.AppendLn(' }'); + Buffer.AppendLn(' )'); + end; + Work(I + 1); + end; + WorkEnd; + if (Length(DefinitionList^) = 0) then + begin + Buffer.AppendLn(Format(' /*0000*/ { %sINVALID }', [PREFIX_MNEMONIC])); + end; + Buffer.AppendLn('};'); + StringList := TStringList.Create; + try + StringList.Text := Buffer.Value; + StringList.SaveToFile(OutputDirectory + FILENAME_INSTRUCTIONDEFINITIONS); + finally + StringList.Free; + end; + finally + Buffer.Free; + end; + + finally + Operands.Free; + end; +end; + +procedure TTableGenerator.GenerateFiles(Editor: TInstructionEditor; const OutputDirectory: String); +var + FilterList: TIndexedFilterList; + DefinitionList: TIndexedDefinitionList; + MnemonicList: TMnemonicList; +begin + // Check error cases + if (not Assigned(Editor.RootTable)) then + begin + raise Exception.Create('The instruction editor does not contain tables.'); + end; + if (Editor.RootTable.HasConflicts) then + begin + raise Exception.Create('The instruction editor has unresolved conflicts.'); + end; + + CreateEntityLists(Editor, FilterList, DefinitionList, MnemonicList); + GenerateInstructionTable(OutputDirectory, @FilterList, FStatistics.FilterCount); + GenerateDefinitionList(OutputDirectory, @DefinitionList); + GenerateMnemonicLists(OutputDirectory, @MnemonicList); +end; + +procedure TTableGenerator.GenerateInstructionTable(const OutputDirectory: String; + const FilterList: PIndexedFilterList; FilterCount: Integer); +var + Buffer: TStringBuffer; + StringList: TStringList; + A: ^TArray; + WorkCount, + IndexShift: Integer; + I, J, K: Integer; +begin + Buffer := TStringBuffer.Create; + try + WorkCount := 0; + WorkStart(woGeneratingFilterFiles, 0, FilterCount); + for I := Low(InstructionFilterClasses) to High(InstructionFilterClasses) do + begin + if (InstructionFilterClasses[I] = TEncodingFilter) then Continue; + IndexShift := 0; + if (InstructionFilterClasses[I].GetNeutralElementType = netPlaceholder) then + begin + IndexShift := 1; + end; + + // Open the filter-array + Buffer.AppendLn(Format('const %s %s%s[][%d] = ', [ + TYPEOF_INSTRUCTIONTABLENODE, PREFIX_FILTERARRAY, + InstructionFilterClasses[I].GetDescription, + Integer(InstructionFilterClasses[I].GetCapacity) - IndexShift])); + Buffer.AppendLn('{'); + + A := nil; + for J := Low(FilterList^) to High(FilterList^) do + begin + if (FilterList^[J].Key = InstructionFilterClasses[I]) then + begin + A := @FilterList^[J].Value; + Break; + end; + end; + + if (Assigned(A)) then + begin + // Add all filters of the current type + for J := Low(A^) to High(A^) do + begin + + // Open the local filter array + Buffer.AppendLn(' {'); + + // Add all filter values of the current filter + for K := IndexShift to High(A^[J].Items) do + begin + Buffer.Append(Format(' /*%.4x*/ ', [K])); + if (A^[J].Items[K].Id < 0) then + begin + Buffer.Append(INSTRUCTIONTABLENODE_INVALID); + end else if (A^[J].Items[K].Filter is TDefinitionContainer) then + begin + Assert((A^[J].Items[K].Filter as TDefinitionContainer).DefinitionCount = 1); + Buffer.Append(Format('%s(0x%.4x)', [ + INSTRUCTIONTABLENODE_DEFINITION, A^[J].Items[K].Id])); + end else + begin + Buffer.Append(Format('%s(%s%s, 0x%.4x)', [ + INSTRUCTIONTABLENODE_FILTER, PREFIX_FILTERTYPE, AnsiUpperCase( + TInstructionFilterClass(A^[J].Items[K].Filter.ClassType).GetDescription), + A^[J].Items[K].Id])); + end; + if (K < High(A^[J].Items)) then + begin + Buffer.AppendLn(','); + end else + begin + Buffer.AppendLn(''); + end; + end; + + // Close the local filter array + Buffer.Append(' }'); + if (J < High(A^)) then + begin + Buffer.AppendLn(','); + end else + begin + Buffer.AppendLn(''); + end; + + Inc(WorkCount); + Work(WorkCount); + end; + end else + begin + Buffer.AppendLn(' {'); + for J := IndexShift to InstructionFilterClasses[I].GetCapacity - 1 do + begin + Buffer.Append(Format(' /*%.4x*/ %s', [J, INSTRUCTIONTABLENODE_INVALID])); + if (J < Integer(InstructionFilterClasses[I].GetCapacity - 1)) then + begin + Buffer.AppendLn(','); + end else + begin + Buffer.AppendLn(''); + end; + end; + Buffer.AppendLn(' }'); + end; + + // Close the filter array + Buffer.AppendLn('};'); + if (I < High(InstructionFilterClasses)) then + begin + Buffer.AppendLn(''); + end; + + end; + WorkEnd; + + StringList := TStringList.Create; + try + StringList.Text := Buffer.Value; + StringList.SaveToFile(OutputDirectory + FILENAME_INSTRUCTIONTABLE); + finally + StringList.Free; + end; + finally + Buffer.Free; + end; +end; + +procedure TTableGenerator.GenerateMnemonicLists(const OutputDirectory: String; + const MnemonicList: PMnemonicList); +var + I: Integer; + MnemonicEnum, + MnemonicStrings: TStringBuffer; + StringList: TStringList; +begin + MnemonicEnum := TStringBuffer.Create; + try + MnemonicStrings := TStringBuffer.Create; + try + WorkStart(woGeneratingMnemonicFiles, 0, Length(MnemonicList^)); + for I := Low(MnemonicList^) to High(MnemonicList^) do + begin + MnemonicEnum.Append(Format(' /*%.4x*/ %s%s', [ + I, PREFIX_MNEMONIC, AnsiUpperCase(MnemonicList^[I])])); + MnemonicStrings.Append(Format(' /*%.4x*/ "%s"', [I, MnemonicList^[I]])); + if (I <> High(MnemonicList^)) then + begin + MnemonicEnum.AppendLn(','); + MnemonicStrings.AppendLn(','); + end else + begin + MnemonicEnum.AppendLn(''); + MnemonicStrings.AppendLn(''); + end; + Work(I + 1); + end; + WorkEnd; + StringList := TStringList.Create; + try + StringList.Text := MnemonicEnum.Value; + StringList.SaveToFile(OutputDirectory + FILENAME_MNEMONICENUM); + StringList.Text := MnemonicStrings.Value; + StringList.SaveToFile(OutputDirectory + FILENAME_MNEMONICSTRINGS); + finally + StringList.Free; + end; + finally + MnemonicStrings.Free; + end; + finally + MnemonicEnum.Free; + end; +end; + +procedure TTableGenerator.Work(WorkCount: Integer); +begin + if (Assigned(FOnWork)) then + begin + FOnWork(Self, WorkCount); + end; +end; + +procedure TTableGenerator.WorkEnd; +begin + if (Assigned(FOnWorkEnd)) then + begin + FOnWorkEnd(Self); + end; +end; + +procedure TTableGenerator.WorkStart(Operation: TGeneratorWorkOperation; MinWorkCount, + MaxWorkCount: Integer); +begin + if (Assigned(FOnWorkStart)) then + begin + FOnWorkStart(Self, Operation, MinWorkCount, MaxWorkCount); + end; +end; +{$ENDREGION} + +end. + diff --git a/assets/InstructionEditor/untInstructionFilters.pas b/assets/InstructionEditor/untInstructionFilters.pas new file mode 100644 index 0000000..e547ebd --- /dev/null +++ b/assets/InstructionEditor/untInstructionFilters.pas @@ -0,0 +1,607 @@ +unit untInstructionFilters; + +interface + +uses + untInstructionEditor; + +type + TOpcodeFilter = class(TInstructionFilter) + public + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetDescription: String; override; + end; + + TEncodingFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TVEXMapFilter = class(TInstructionFilter) + public + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TXOPMapFilter = class(TInstructionFilter) + public + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TModeFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TMandatoryPrefixFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TModrmModFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TModrmRegFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TModrmRmFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TOperandSizeFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TAddressSizeFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TRexWFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TVexLFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TEvexL2Filter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + + TEvexBFilter = class(TInstructionFilter) + public + class function GetNeutralElementType: TNeutralElementType; override; + class function GetCapacity: Cardinal; override; + class function GetInsertPosition(const Definition: TInstructionDefinition): Integer; override; + class function GetItemDescription(Index: Integer): String; override; + class function GetDescription: String; override; + end; + +const + InstructionFilterClasses: array[0..14] of TInstructionFilterClass = + ( + TOpcodeFilter, + TEncodingFilter, + TVEXMapFilter, + TXOPMapFilter, + TModeFilter, + TMandatoryPrefixFilter, + TModrmModFilter, + TModrmRegFilter, + TModrmRmFilter, + TOperandSizeFilter, + TAddressSizeFilter, + TRexWFilter, + TVexLFilter, + TEvexL2Filter, + TEvexBFilter + ); + +implementation + +uses + System.SysUtils, System.TypInfo; + +{$REGION 'Class: TOpcodeFilter'} +class function TOpcodeFilter.GetCapacity: Cardinal; +begin + Result := 256; +end; + +class function TOpcodeFilter.GetDescription: String; +begin + Result := 'Opcode'; +end; + +class function TOpcodeFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Result := Definition.Opcode; +end; +{$ENDREGION} + +{$REGION 'Class: TEncodingFilter'} +class function TEncodingFilter.GetCapacity: Cardinal; +begin + Result := 5; +end; + +class function TEncodingFilter.GetDescription: String; +begin + Result := 'Encoding'; +end; + +class function TEncodingFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.Encoding); +end; + +class function TEncodingFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TInstructionEncoding), Index); +end; + +class function TEncodingFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netValue; +end; +{$ENDREGION} + +{$REGION 'Class: TVEXMapFilter'} +class function TVEXMapFilter.GetCapacity: Cardinal; +begin + Result := 16; +end; + +class function TVEXMapFilter.GetDescription: String; +begin + Result := 'VEX'; +end; + +class function TVEXMapFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Assert(Definition.OpcodeMap < omXOP8); + Result := (Integer(Definition.OpcodeExtensions.MandatoryPrefix)) * 4 + Byte(Definition.OpcodeMap); +end; + +class function TVEXMapFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + case (Index div 4) of + 0: Result := '##'; + 1: Result := '66'; + 2: Result := 'F3'; + 3: Result := 'F2'; + end; + case (Index mod 4) of + 0: Result := Result + ' default'; + 1: Result := Result + ' 0F'; + 2: Result := Result + ' 0F 38'; + 3: Result := Result + ' 0F 3A'; + end; +end; +{$ENDREGION} + +{$REGION 'Class: TXOPMapFilter'} +class function TXOPMapFilter.GetCapacity: Cardinal; +begin + Result := 4; +end; + +class function TXOPMapFilter.GetDescription: String; +begin + Result := 'XOP'; +end; + +class function TXOPMapFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Assert(Definition.Encoding = ieXOP); + Assert(Definition.OpcodeMap >= omXOP8); + Result := Integer(Definition.OpcodeMap) - Integer(omXOP8) + 1; +end; + +class function TXOPMapFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + if (Index = 0) then + begin + Result := 'Non-XOP-Placeholder'; + end else + begin + Result := GetEnumName(TypeInfo(TOpcodeMap), Integer(omXOP8) + Index - 1); + end; +end; +{$ENDREGION} + +{$REGION 'Class: TModeFilter'} +class function TModeFilter.GetCapacity: Cardinal; +begin + Result := 3; +end; + +class function TModeFilter.GetDescription: String; +begin + Result := 'Mode'; +end; + +class function TModeFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.OpcodeExtensions.Mode); +end; + +class function TModeFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TExtInstructionMode), Index); +end; + +class function TModeFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netPlaceholder; +end; +{$ENDREGION} + +{$REGION 'Class: TMandatoryPrefixFilter'} +class function TMandatoryPrefixFilter.GetCapacity: Cardinal; +begin + Result := 4; +end; + +class function TMandatoryPrefixFilter.GetDescription: String; +begin + Result := 'MandatoryPrefix'; +end; + +class function TMandatoryPrefixFilter.GetInsertPosition( + const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.OpcodeExtensions.MandatoryPrefix); +end; + +class function TMandatoryPrefixFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TExtMandatoryPrefix), Index); +end; + +class function TMandatoryPrefixFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netValue; +end; +{$ENDREGION} + +{$REGION 'Class: TModrmModFilter'} +class function TModrmModFilter.GetCapacity: Cardinal; +begin + Result := 3; +end; + +class function TModrmModFilter.GetDescription: String; +begin + Result := 'ModrmMod'; +end; + +class function TModrmModFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.OpcodeExtensions.ModrmMod); +end; + +class function TModrmModFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TExtModrmMod), Index); +end; + +class function TModrmModFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netPlaceholder; +end; +{$ENDREGION} + +{$REGION 'Class: TModrmRegFilter'} +class function TModrmRegFilter.GetCapacity: Cardinal; +begin + Result := 9; +end; + +class function TModrmRegFilter.GetDescription: String; +begin + Result := 'ModrmReg'; +end; + +class function TModrmRegFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.OpcodeExtensions.ModrmReg); +end; + +class function TModrmRegFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TExtModrmReg), Index); +end; + +class function TModrmRegFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netPlaceholder; +end; +{$ENDREGION} + +{$REGION 'Class: TModrmRmFilter'} +class function TModrmRmFilter.GetCapacity: Cardinal; +begin + Result := 9; +end; + +class function TModrmRmFilter.GetDescription: String; +begin + Result := 'ModrmRm'; +end; + +class function TModrmRmFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.OpcodeExtensions.ModrmRm); +end; + +class function TModrmRmFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TExtModrmRm), Index); +end; + +class function TModrmRmFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netPlaceholder; +end; +{$ENDREGION} + +{$REGION 'Class: TOperandSizeFilter'} +class function TOperandSizeFilter.GetCapacity: Cardinal; +begin + Result := 3; +end; + +class function TOperandSizeFilter.GetDescription: String; +begin + Result := 'OperandSize'; +end; + +class function TOperandSizeFilter.GetInsertPosition( + const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.OpcodeExtensions.OperandSize); +end; + +class function TOperandSizeFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TExtOperandSize), Index); +end; + +class function TOperandSizeFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netPlaceholder; +end; +{$ENDREGION} + +{$REGION 'Class: TAddressSizeFilter'} +class function TAddressSizeFilter.GetCapacity: Cardinal; +begin + Result := 4; +end; + +class function TAddressSizeFilter.GetDescription: String; +begin + Result := 'AddressSize'; +end; + +class function TAddressSizeFilter.GetInsertPosition( + const Definition: TInstructionDefinition): Integer; +begin + Result := Integer(Definition.OpcodeExtensions.AddressSize); +end; + +class function TAddressSizeFilter.GetItemDescription(Index: Integer): String; +begin + Assert((Index >= 0) and (Index < Integer(GetCapacity))); + Result := GetEnumName(TypeInfo(TExtAddressSize), Index); +end; + +class function TAddressSizeFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netPlaceholder; +end; +{$ENDREGION} + +{$REGION 'Class: TRexWFilter'} +class function TRexWFilter.GetCapacity: Cardinal; +begin + Result := 2; +end; + +class function TRexWFilter.GetDescription: String; +begin + Result := 'REXW'; +end; + +class function TRexWFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + if (bfRexW in Definition.OpcodeExtensions.BitFilters) then + begin + Result := 1; + end else + begin + Result := 0; + end; +end; + +class function TRexWFilter.GetItemDescription(Index: Integer): String; +begin + Result := 'REX.W ' + IntToStr(Index); +end; + +class function TRexWFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netValue; +end; +{$ENDREGION} + +{$REGION 'Class: TVexLFilter'} +class function TVexLFilter.GetCapacity: Cardinal; +begin + Result := 2; +end; + +class function TVexLFilter.GetDescription: String; +begin + Result := 'VEXL'; +end; + +class function TVexLFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + if (bfVexL in Definition.OpcodeExtensions.BitFilters) then + begin + Result := 1; + end else + begin + Result := 0; + end; +end; + +class function TVexLFilter.GetItemDescription(Index: Integer): String; +begin + Result := 'VEX.L ' + IntToStr(Index); +end; + +class function TVexLFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netValue; +end; +{$ENDREGION} + +{$REGION 'Class: TEvexL2Filter'} +class function TEvexL2Filter.GetCapacity: Cardinal; +begin + Result := 2; +end; + +class function TEvexL2Filter.GetDescription: String; +begin + Result := 'EVEXL2'; +end; + +class function TEvexL2Filter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + if (bfEvexL2 in Definition.OpcodeExtensions.BitFilters) then + begin + Result := 1; + end else + begin + Result := 0; + end; +end; + +class function TEvexL2Filter.GetItemDescription(Index: Integer): String; +begin + Result := 'EVEX.L'' ' + IntToStr(Index); +end; + +class function TEvexL2Filter.GetNeutralElementType: TNeutralElementType; +begin + Result := netValue; +end; +{$ENDREGION} + +{$REGION 'Class: TEvexBFilter'} +class function TEvexBFilter.GetCapacity: Cardinal; +begin + Result := 2; +end; + +class function TEvexBFilter.GetDescription: String; +begin + Result := 'EVEXB'; +end; + +class function TEvexBFilter.GetInsertPosition(const Definition: TInstructionDefinition): Integer; +begin + if (bfEvexB in Definition.OpcodeExtensions.BitFilters) then + begin + Result := 1; + end else + begin + Result := 0; + end; +end; + +class function TEvexBFilter.GetItemDescription(Index: Integer): String; +begin + Result := 'EVEX.B ' + IntToStr(Index); +end; + +class function TEvexBFilter.GetNeutralElementType: TNeutralElementType; +begin + Result := netValue; +end; +{$ENDREGION} + +end. diff --git a/assets/InstructionEditor/untPropertyEditors.pas b/assets/InstructionEditor/untPropertyEditors.pas new file mode 100644 index 0000000..88a4e71 --- /dev/null +++ b/assets/InstructionEditor/untPropertyEditors.pas @@ -0,0 +1,384 @@ +unit untPropertyEditors; + +interface + +uses + cxOI; + +type + TOpcodeByteProperty = class(TcxOrdinalProperty) + public + function GetValue: String; override; + procedure SetValue(const Value: String); override; + end; + + TCPUIDFeatureFlagsProperty = class(TcxClassProperty) + public + procedure Edit; override; + function GetAttributes: TcxPropertyAttributes; override; + function GetValue: String; override; + procedure SetValue(const Value: String); override; + function IsDefaultValue: Boolean; override; + end; + + TX86RegistersProperty = class(TcxClassProperty) + public + procedure Edit; override; + function GetAttributes: TcxPropertyAttributes; override; + function GetValue: String; override; + procedure SetValue(const Value: String); override; + function IsDefaultValue: Boolean; override; + end; + + TInstructionOperandProperty = class(TcxClassProperty) + public + function GetAttributes: TcxPropertyAttributes; override; + function GetValue: String; override; + procedure SetValue(const Value: String); override; + function IsDefaultValue: Boolean; override; + end; + + TInstructionOperandsProperty = class(TcxClassProperty) + public + procedure Edit; override; + function GetAttributes: TcxPropertyAttributes; override; + end; + +implementation + +uses + System.SysUtils, System.TypInfo, System.Classes, Vcl.Forms, untInstructionEditor, + untHelperClasses, formEditorCPUIDFeatureFlags, formEditorX86Registers, + formEditorInstructionOperands, cxButtonEdit; + +{ TOpcodeByteProperty } + +function TOpcodeByteProperty.GetValue: String; +begin + Result := IntToHex(GetOrdValue, 2); +end; + +procedure TOpcodeByteProperty.SetValue(const Value: String); +var + V: Integer; +begin + if (not TryStrToInt('$' + Value, V)) then + begin + raise Exception.CreateFmt('"%s" is not a valid hexadecimal value.', [Value]); + end; + if (V < 0) or (V > 255) then + begin + raise Exception.Create('Value has to be between 0 and 255.'); + end; + SetOrdValue(V); +end; + +{ TCPUIDFeatureFlagsProperty } + +procedure TCPUIDFeatureFlagsProperty.Edit; +var + Form: TfrmEditorCPUIDFeatureFlags; +begin + Form := TfrmEditorCPUIDFeatureFlags.Create(Application); + try + Form.Caption := GetComponent(0).GetNamePath + '.' + GetName; + Form.FeatureFlags := TCPUIDFeatureFlags(GetOrdValue).FeatureFlags; + Form.ShowModal; + if (Form.ApplyChanges) then + begin + TCPUIDFeatureFlags(GetOrdValue).FeatureFlags := Form.FeatureFlags; + PostChangedNotification; + end; + finally + Form.Free; + end; +end; + +function TCPUIDFeatureFlagsProperty.GetAttributes: TcxPropertyAttributes; +begin + Result := [ipaDialog]; +end; + +function TCPUIDFeatureFlagsProperty.GetValue: String; +var + CPUIDFeatureFlags: TCPUIDFeatureFlagSet; + CPUIDFeatureFlag: TCPUIDFeatureFlag; + S: String; +begin + Result := 'NONE'; + CPUIDFeatureFlags := TCPUIDFeatureFlags(GetOrdValue).FeatureFlags; + if (CPUIDFeatureFlags <> []) then + begin + Result := ''; + for CPUIDFeatureFlag in CPUIDFeatureFlags do + begin + S := GetEnumName(TypeInfo(TCPUIDFeatureFlag), Ord(CPUIDFeatureFlag)); + Delete(S, 1, 2); + Result := Result + S + ', '; + end; + if (Result <> '') then + begin + Delete(Result, Length(Result) - 1, 2); + end; + end; +end; + +function TCPUIDFeatureFlagsProperty.IsDefaultValue: Boolean; +begin + Result := (TCPUIDFeatureFlags(GetOrdValue).FeatureFlags = []); +end; + +procedure TCPUIDFeatureFlagsProperty.SetValue(const Value: String); +var + S: String; + I: Integer; + C: Char; + A: TArray; + F: TCPUIDFeatureFlag; + FeatureFlags: TCPUIDFeatureFlagSet; +begin + if (Value = '') then + begin + TCPUIDFeatureFlags(GetOrdValue).FeatureFlags := []; + Exit; + end; + SetLength(S, Length(Value)); + I := 1; + for C in Value do + begin + if (CharInSet(C, ['a'..'z', 'A'..'Z', '0'..'9', ','])) then + begin + S[I] := C; + Inc(I); + end; + end; + SetLength(S, I - 1); + TStringHelper.AnsiLowerCase(S); + A := S.Split([',']); + FeatureFlags := []; + for F := Low(TCPUIDFeatureFlag) to High(TCPUIDFeatureFlag) do + begin + S := GetEnumName(TypeInfo(TCPUIDFeatureFlag), Ord(F)); + Delete(S, 1, 2); + TStringHelper.AnsiLowerCase(S); + for I := Low(A) to High(A) do + begin + if (A[I] = S) then + begin + Include(FeatureFlags, F); + end; + end; + end; + TCPUIDFeatureFlags(GetOrdValue).FeatureFlags := FeatureFlags; +end; + +{ TX86RegistersProperty } + +procedure TX86RegistersProperty.Edit; +var + Form: TfrmEditorX86Registers; +begin + Form := TfrmEditorX86Registers.Create(Application); + try + Form.Caption := GetComponent(0).GetNamePath + '.' + GetName; + Form.Registers := TX86Registers(GetOrdValue).Registers; + Form.ShowModal; + if (Form.ApplyChanges) then + begin + TX86Registers(GetOrdValue).Registers := Form.Registers; + PostChangedNotification; + end; + finally + Form.Free; + end; +end; + +function TX86RegistersProperty.GetAttributes: TcxPropertyAttributes; +begin + Result := [ipaDialog]; +end; + +function TX86RegistersProperty.GetValue: String; +var + X86Registers: TX86RegisterSet; + X86Register: TX86Register; + S: String; +begin + Result := 'NONE'; + X86Registers := TX86Registers(GetOrdValue).Registers; + if (TX86Registers(GetOrdValue).Registers <> []) and + (TX86Registers(GetOrdValue).Registers <> [regNone]) then + begin + Result := ''; + for X86Register in X86Registers do + begin + S := GetEnumName(TypeInfo(TX86Register), Ord(X86Register)); + Delete(S, 1, 3); + Result := Result + S + ', '; + end; + if (Result <> '') then + begin + Delete(Result, Length(Result) - 1, 2); + end; + end; +end; + +function TX86RegistersProperty.IsDefaultValue: Boolean; +begin + Result := (TX86Registers(GetOrdValue).Registers = []) or + (TX86Registers(GetOrdValue).Registers = [regNone]) +end; + +procedure TX86RegistersProperty.SetValue(const Value: String); +var + S: String; + I: Integer; + C: Char; + A: TArray; + R: TX86Register; + Registers: TX86RegisterSet; +begin + if (Value = '') then + begin + TX86Registers(GetOrdValue).Registers := []; + Exit; + end; + SetLength(S, Length(Value)); + I := 1; + for C in Value do + begin + if (CharInSet(C, ['a'..'z', 'A'..'Z', '0'..'9', ','])) then + begin + S[I] := C; + Inc(I); + end; + end; + SetLength(S, I - 1); + TStringHelper.AnsiLowerCase(S); + A := S.Split([',']); + Registers := []; + for R := Low(TX86Register) to High(TX86Register) do + begin + S := GetEnumName(TypeInfo(TX86Register), Ord(R)); + Delete(S, 1, 3); + TStringHelper.AnsiLowerCase(S); + for I := Low(A) to High(A) do + begin + if (A[I] = S) then + begin + Include(Registers, R); + end; + end; + end; + TX86Registers(GetOrdValue).Registers := Registers; +end; + +{ TInstructionOperandProperty } + +function TInstructionOperandProperty.GetAttributes: TcxPropertyAttributes; +begin + Result := [ipaSubProperties]; +end; + +function TInstructionOperandProperty.GetValue: String; +begin + Result := TInstructionOperand(GetOrdValue).GetDescription; + if (TInstructionOperand(GetOrdValue).OperandType = optUnused) then + begin + Result := 'unused'; + end; +end; + +function TInstructionOperandProperty.IsDefaultValue: Boolean; +begin + Result := (TInstructionOperand(GetOrdValue).OperandType = optUnused); +end; + +procedure TInstructionOperandProperty.SetValue(const Value: String); +var + S, R: String; + I: Integer; + C: Char; + A: TArray; + T: TOperandType; +begin + if (Value = '') then + begin + TInstructionOperand(GetOrdValue).OperandType := optUnused; + Exit; + end; + SetLength(S, Length(Value)); + I := 1; + for C in Value do + begin + if (CharInSet(C, ['a'..'z', 'A'..'Z', '0'..'9', '('])) then + begin + S[I] := C; + Inc(I); + end; + end; + SetLength(S, I - 1); + TStringHelper.AnsiLowerCase(S); + A := S.Split(['(']); + for T := Low(TOperandType) to High(TOperandType) do + begin + R := GetEnumName(TypeInfo(TOperandType), Ord(T)); + Delete(R, 1, 3); + TStringHelper.AnsiLowerCase(R); + if (A[0] = R) then + begin + TInstructionOperand(GetOrdValue).OperandType := T; + Break; + end; + end; + if (Length(A) >= 1) then + begin + if (A[1] = 'r') then TInstructionOperand(GetOrdValue).AccessMode := opaRead + else if (A[1] = 'w') then TInstructionOperand(GetOrdValue).AccessMode := opaWrite + else if (A[1] = 'rw') then TInstructionOperand(GetOrdValue).AccessMode := opaReadWrite; + end; +end; + +{ TInstructionOperandsProperty } + +procedure TInstructionOperandsProperty.Edit; +var + Form: TfrmEditorInstructionOperands; +begin + Form := TfrmEditorInstructionOperands.Create(Application); + try + Form.Caption := GetComponent(0).GetNamePath + '.' + GetName; + Form.Operands := TInstructionOperands(GetOrdValue); + Form.ShowModal; + if (Form.ApplyChanges) then + begin + TInstructionOperands(GetOrdValue).Assign(Form.Operands); + PostChangedNotification; + end; + finally + Form.Free; + end; +end; + +function TInstructionOperandsProperty.GetAttributes: TcxPropertyAttributes; +begin + Result := [ipaDialog, ipaSubProperties]; +end; + +initialization + // Register custom property editor for hexadecimal display of TOpcodeByte values + cxRegisterPropertyEditor(TypeInfo(TOpcodeByte), nil, '', TOpcodeByteProperty); + + // Register custom property editors for easy modification of the instruction-operands + cxRegisterPropertyEditor(TypeInfo(TInstructionOperand), nil, '', TInstructionOperandProperty); + cxRegisterPropertyEditor(TypeInfo(TInstructionOperands), nil, '', TInstructionOperandsProperty); + cxRegisterEditPropertiesClass(TInstructionOperandsProperty, TcxButtonEditProperties); + + // Delphi does not allow sets > 4 bytes as published values, so we have to use a wrapper class + // and a custom editor + cxRegisterPropertyEditor(TypeInfo(TCPUIDFeatureFlags), nil, '', TCPUIDFeatureFlagsProperty); + cxRegisterEditPropertiesClass(TCPUIDFeatureFlagsProperty, TcxButtonEditProperties); + cxRegisterPropertyEditor(TypeInfo(TX86Registers), nil, '', TX86RegistersProperty); + cxRegisterEditPropertiesClass(TX86RegistersProperty, TcxButtonEditProperties); + +end. diff --git a/assets/InstructionEditor/untPropertyHints.pas b/assets/InstructionEditor/untPropertyHints.pas new file mode 100644 index 0000000..7d690a4 --- /dev/null +++ b/assets/InstructionEditor/untPropertyHints.pas @@ -0,0 +1,75 @@ +unit untPropertyHints; + +interface + +function GetPropertyHint(const PropertyId: String): String; + +implementation + +type + TPropertyHint = record + public + PropertyId: String; + PropertyHint: String; + end; + +const + PropertyHints: array[0..7] of TPropertyHint = + ( + ( + PropertyId : 'Filter.FilterType'; + PropertyHint: 'The filter type.' + ), + ( + PropertyId : 'Filter.FilterFlags'; + PropertyHint: 'The filter flags.' + ), + ( + PropertyId : 'Filter.FilterFlags.iffIsRootTable'; + PropertyHint: 'This is the root table.' + ), + ( + PropertyId : 'Filter.FilterFlags.iffIsStaticFilter'; + PropertyHint: 'This is a static filter that should not be removed.' + ), + ( + PropertyId : 'Filter.FilterFlags.iffIsDefinitionContainer'; + PropertyHint: 'This is a definition container and not an actual filter.' + ), + ( + PropertyId : 'Filter.NeutralElementType'; + PropertyHint: 'The neutral element type of the filter. Possible values:' + #13#10#13#10 + + '- netNotAvailable' + #13#10 + + 'The neutral "zero" element is not supported.' + #13#10 + + '- netPlaceholder' + #13#10 + + 'The neutral "zero" element is supported and used as a placeholder. ' + + 'The filter will signal a conflict, if the neutral element AND at least one ' + + 'regular value is set.' + #13#10 + + '- netValue' + #13#10 + + 'The neutral "zero" element is supported and can be used as a regular value.' + ), + ( + PropertyId : 'Filter.Capacity'; + PropertyHint: 'The maximum capacity of the filter.' + ), + ( + PropertyId : 'Filter.ItemCount'; + PropertyHint: 'The actual number of non-empty slots in the filter.' + ) + ); + +function GetPropertyHint(const PropertyId: String): String; +var + I: Integer; +begin + Result := 'No info text available.'; + for I := Low(PropertyHints) to High(PropertyHints) do + begin + if (PropertyHints[I].PropertyId = PropertyId) then + begin + Exit(PropertyHints[I].PropertyHint); + end; + end; +end; + +end. diff --git a/assets/InstructionEditor/untTableGenerator.pas b/assets/InstructionEditor/untTableGenerator.pas new file mode 100644 index 0000000..c926779 --- /dev/null +++ b/assets/InstructionEditor/untTableGenerator.pas @@ -0,0 +1,350 @@ +unit untTableGenerator; + +interface + +uses + System.Classes, System.Generics.Collections, untInstructionEditor; + +type + TTableGeneratorInfo = record + public + FilterCount: Integer; + DefinitionCount: Integer; + MnemonicCount: Integer; + FilterSize: Cardinal; + DefinitionSize: Cardinal; + MnemonicSize: Cardinal; + end; + + TWorkOperation = ( + woIndexingFilters, + woIndexingDefinitions, + woGeneratingFilterFiles, + woGeneratingDefinitionFiles + ); + + TWorkStartEvent = procedure(Sender: TObject; Operation: TWorkOperation; + MinWorkCount, MaxWorkCount: Integer) of Object; + TWorkEvent = procedure(Sender: TObject; WorkCount: Integer) of Object; + + TTableGenerator = class(TObject) + strict private type + TInstructionFilterMap = TObjectDictionary>; + strict private + FFilterMap: TInstructionFilterMap; + FFilterCount: Integer; + FDefinitionCount: Integer; + FMnemonicCount: Integer; + FFilterSize: Cardinal; + FDefinitionSize: Cardinal; + FMnemonicSize: Cardinal; + strict private + FOnWorkStart: TWorkStartEvent; + FOnWork: TWorkEvent; + FOnWorkEnd: TNotifyEvent; + strict private + procedure EditorFilterCreated(Sender: TObject; Filter: TInstructionFilter); + strict private + procedure WorkStart(Operation: TWorkOperation; MinWorkCount, MaxWorkCount: Integer); inline; + procedure Work(WorkCount: Integer); inline; + procedure WorkEnd; inline; + strict private + procedure FinalizeFilterTables(Editor: TInstructionEditor); + + function GetNameForTable(FilterClass: TInstructionFilterClass): String; inline; + function GetNameForType(FilterClass: TInstructionFilterClass): String; inline; + procedure GenerateFilterFiles(const OutputDirectory: String; + FilterMap: TInstructionFilterMap; Definitions: TList; + FilterCount: Integer); + procedure GenerateDefinitionFiles(const OutputDirectory: String; + Definitions: TList); + public + procedure GenerateFiles(Editor: TInstructionEditor; const OutputDirectory: String); + public + property FilterCount: Integer read FFilterCount; + property DefinitionCount: Integer read FDefinitionCount; + property MnemonicCount: Integer read FMnemonicCount; + property FilterSize: Cardinal read FFilterSize; + property DefinitionSize: Cardinal read FDefinitionSize; + property MnemonicSize: Cardinal read FMnemonicSize; + public + property OnWorkStart: TWorkStartEvent read FOnWorkStart write FOnWorkStart; + property OnWork: TWorkEvent read FOnWork write FOnWork; + property OnWorkEnd: TNotifyEvent read FOnWorkEnd write FOnWorkEnd; + end; + +implementation + +uses + System.SysUtils, System.Generics.Defaults, untInstructionFilters, untHelperClasses; + +const + FILENAME_FILTERTABLES = 'InstructionTable.inc'; + FILTERARRAY_PREFIX_NAME = 'filter'; + FILTERARRAY_PREFIX_TYPENAME = 'ZYDIS_NODETYPE_FILTER_'; + FILTERARRAY_ITEMTYPE = 'ZydisInstructionTableNode'; + FILTERARRAY_MACRO_INVALID = 'ZYDIS_INVALID'; + FILTERARRAY_MACRO_FILTER = 'ZYDIS_FILTER'; + FILTERARRAY_MACRO_DEFINITION = 'ZYDIS_DEFINITION'; + FILTERARRAY_ITEM_SIZE = 3; + +{ TTableGenerator } + +procedure TTableGenerator.EditorFilterCreated(Sender: TObject; Filter: TInstructionFilter); +var + List: TList; +begin + if (Filter.IsDefinitionContainer) or (Filter is TEncodingFilter) then Exit; + if (FFilterMap.ContainsKey(TInstructionFilterClass(Filter.ClassType))) then + begin + List := FFilterMap[TInstructionFilterClass(Filter.ClassType)]; + end else + begin + List := TList.Create; + FFilterMap.Add(TInstructionFilterClass(Filter.ClassType), List); + end; + Filter.Data := Pointer(List.Count); + List.Add(Filter); + Inc(FFilterCount); + if (Filter.NeutralElementType in [netNotAvailable, netValue]) then + begin + Inc(FFilterSize, Filter.GetCapacity * FILTERARRAY_ITEM_SIZE); + end else + begin + Inc(FFilterSize, (Filter.GetCapacity - 1) * FILTERARRAY_ITEM_SIZE); + end; +end; + +procedure TTableGenerator.FinalizeFilterTables(Editor: TInstructionEditor); +begin + // Get rid of all encoding-filters as they are only needed in the editor + // Move LES instruction into the first field of the 3-byte vex-filter + Assert(not Assigned(Editor.RootTable.Items[$C4].Items[$03].Items[$00])); + Editor.RootTable.Items[$C4].Items[$03].SetItem($00, Editor.RootTable.Items[$C4].Items[$00]); + // Move LDS instruction into the first field of the 2-byte vex-filter + Assert(not Assigned(Editor.RootTable.Items[$C5].Items[$03].Items[$00])); + Editor.RootTable.Items[$C5].Items[$03].SetItem($00, Editor.RootTable.Items[$C5].Items[$00]); + // Move BOUND instruction into the first field of the evex-filter + Assert(not Assigned(Editor.RootTable.Items[$62].Items[$04].Items[$00])); + Editor.RootTable.Items[$62].Items[$04].SetItem($00, Editor.RootTable.Items[$62].Items[$00]); + // Move POP instruction into the first field of the xop-filter + Assert(not Assigned(Editor.RootTable.Items[$8F].Items[$02].Items[$00])); + Editor.RootTable.Items[$8F].Items[$02].SetItem($00, Editor.RootTable.Items[$8F].Items[$00]); + // Remove the encoding-filter for 3DNow instructions + Editor.RootTable.Items[$0F].SetItem($0F, Editor.RootTable.Items[$0F].Items[$0F].Items[$01]); + // Remove the encoding-filter for 3-byte VEX instructions + Editor.RootTable.SetItem($C4, Editor.RootTable.Items[$C4].Items[$03]); + // Remove the encoding-filter for 2-byte VEX instructions + Editor.RootTable.SetItem($C5, Editor.RootTable.Items[$C5].Items[$03]); + // Remove the encoding-filter for EVEX instructions + Editor.RootTable.SetItem($62, Editor.RootTable.Items[$62].Items[$04]); + // Remove the encoding-filter for XOP instructions + Editor.RootTable.SetItem($8F, Editor.RootTable.Items[$8f].Items[$02]); +end; + +procedure TTableGenerator.GenerateDefinitionFiles(const OutputDirectory: String; + Definitions: TList); +begin + WorkStart(woGeneratingDefinitionFiles, 0, Definitions.Count); + + WorkEnd; +end; + +procedure TTableGenerator.GenerateFiles(Editor: TInstructionEditor; const OutputDirectory: String); +var + E: TInstructionEditor; + D: TInstructionDefinition; + I: Integer; + Definitions: TList; + Comparison: TComparison; +begin + if (not Assigned(Editor.RootTable)) then + begin + raise Exception.Create('The instruction editor does not contain tables.'); + end; + if (Editor.RootTable.HasConflicts) then + begin + //raise Exception.Create('The instruction editor has unresolved conflicts.'); + end; + FDefinitionCount := Editor.DefinitionCount; + E := TInstructionEditor.Create; + try + E.OnFilterCreated := EditorFilterCreated; + E.BeginUpdate; + try + FFilterMap := TObjectDictionary>.Create([doOwnsValues]); + try + E.Reset; + // Create filter indizes by copying all definitions to the internal editor instance + WorkStart(woIndexingFilters, 0, Editor.DefinitionCount); + for I := 0 to Editor.DefinitionCount - 1 do + begin + D := E.CreateDefinition('unnamed'); + D.Assign(Editor.Definitions[I]); + Work(I + 1); + end; + WorkEnd; + FinalizeFilterTables(E); + Definitions := TList.Create; + try + // Create definition indizes and a sorted definition-list + WorkStart(woIndexingDefinitions, 0, E.DefinitionCount * 2); + for I := 0 to E.DefinitionCount - 1 do + begin + Definitions.Add(E.Definitions[I]); + Work(I + 1); + end; + Comparison := + function(const Left, Right: TInstructionDefinition): Integer + begin + Result := CompareStr(Left.Mnemonic, Right.Mnemonic); + end; + Definitions.Sort(TComparer.Construct(Comparison)); + for I := 0 to Definitions.Count - 1 do + begin + Definitions[I].Data := Pointer(I); + Work(E.DefinitionCount + I + 1); + end; + WorkEnd; + // Generate files + GenerateFilterFiles(OutputDirectory, FFilterMap, Definitions, E.FilterCount); + GenerateDefinitionFiles(OutputDirectory, Definitions); + finally + Definitions.Free; + end; + finally + FFilterMap.Free; + end; + finally + E.EndUpdate; + end; + finally + E.Free; + end; +end; + +procedure TTableGenerator.GenerateFilterFiles(const OutputDirectory: String; + FilterMap: TInstructionFilterMap; Definitions: TList; + FilterCount: Integer); +var + WorkCount, IndexShift: Integer; + Buffer: TStringBuffer; + StringList: TStringList; + I, J, K: Integer; + FilterList: TList; +begin + Buffer := TStringBuffer.Create; + try + WorkCount := 0; + WorkStart(woGeneratingFilterFiles, 0, FilterCount); + for I := Low(InstructionFilterClasses) to High(InstructionFilterClasses) do + begin + IndexShift := 1; + if (InstructionFilterClasses[I].GetNeutralElementType in [netNotAvailable, netValue]) then + begin + IndexShift := 0; + end; + Buffer.AppendLn(Format('const %s %s%s[][%d] = ', [ + FILTERARRAY_ITEMTYPE, + FILTERARRAY_PREFIX_NAME, GetNameForTable(InstructionFilterClasses[I]), + Integer(InstructionFilterClasses[I].GetCapacity) - IndexShift])); + Buffer.AppendLn('{'); + if (FilterMap.ContainsKey(InstructionFilterClasses[I])) then + begin + FilterList := FilterMap[InstructionFilterClasses[I]]; + for J := 0 to FilterList.Count - 1 do + begin + Buffer.AppendLn(' {'); + for K := IndexShift to FilterList[J].Capacity - 1 do + begin + Buffer.Append(Format(' /*%.4x*/ ', [K])); + if (not Assigned(FilterList[J].Items[K])) then + begin + Buffer.Append(FILTERARRAY_MACRO_INVALID); + end else if (FilterList[J].Items[K] is TDefinitionContainer) then + begin + Assert((FilterList[J].Items[K] as TDefinitionContainer).DefinitionCount > 0); + Buffer.Append(Format('%s(0x%.4x)', [FILTERARRAY_MACRO_DEFINITION, + Integer((FilterList[J].Items[K] as TDefinitionContainer).Definitions[0].Data)])); + end else + begin + Buffer.Append(Format('%s(%s%s, 0x%.4x)', [FILTERARRAY_MACRO_FILTER, + FILTERARRAY_PREFIX_TYPENAME, + GetNameForType(TInstructionFilterClass(FilterList[J].Items[K].ClassType)), + Integer(FilterList[J].Items[K].Data)])); + end; + if (K < Integer(FilterList[J].Capacity - 1)) then + begin + Buffer.AppendLn(','); + end else + begin + Buffer.AppendLn(''); + end; + end; + Buffer.Append(' }'); + if (J < FilterList.Count - 1) then + begin + Buffer.AppendLn(','); + end else + begin + Buffer.AppendLn(''); + end; + Inc(WorkCount); + Work(WorkCount); + end; + end; + Buffer.AppendLn('};'); + if (I < High(InstructionFilterClasses)) then + begin + Buffer.AppendLn(''); + end; + end; + WorkEnd; + StringList := TStringList.Create; + try + StringList.Text := Buffer.Value; + StringList.SaveToFile(IncludeTrailingPathDelimiter(OutputDirectory) + FILENAME_FILTERTABLES); + finally + StringList.Free; + end; + finally + Buffer.Free; + end; +end; + +function TTableGenerator.GetNameForTable(FilterClass: TInstructionFilterClass): String; +begin + Result := FilterClass.GetDescription; +end; + +function TTableGenerator.GetNameForType(FilterClass: TInstructionFilterClass): String; +begin + Result := AnsiUpperCase(FilterClass.GetDescription); +end; + +procedure TTableGenerator.Work(WorkCount: Integer); +begin + if (Assigned(FOnWork)) then + begin + FOnWork(Self, WorkCount); + end; +end; + +procedure TTableGenerator.WorkEnd; +begin + if (Assigned(FOnWorkEnd)) then + begin + FOnWorkEnd(Self); + end; +end; + +procedure TTableGenerator.WorkStart(Operation: TWorkOperation; MinWorkCount, MaxWorkCount: Integer); +begin + if (Assigned(FOnWorkStart)) then + begin + FOnWorkStart(Self, Operation, MinWorkCount, MaxWorkCount); + end; +end; + +end.