├── UnZ ├── Program.vb ├── My Project │ ├── launchSettings.json │ └── PublishProfiles │ │ ├── SingleFile_linux-arm.pubxml.user │ │ ├── SingleFile_win-arm.pubxml.user │ │ ├── SingleFile_win-x86.pubxml.user │ │ ├── SingleFile_linux-x64.pubxml.user │ │ ├── SingleFile_osx-x64.pubxml.user │ │ ├── SingleFile_osx-x64.pubxml │ │ ├── SingleFile_linux-arm.pubxml │ │ ├── SingleFile_linux-x64.pubxml │ │ ├── SingleFile_win-arm.pubxml │ │ ├── SingleFile_win-x86.pubxml │ │ ├── SingleFile_win-x64.pubxml │ │ └── SingleFile_win-x64.pubxml.user ├── UnZ.vbproj ├── MemoryMap.vb ├── Helper.vb ├── PropertyAnalyser.vb └── Decode.vb ├── LICENSE ├── UnZ.sln └── README.md /UnZ/Program.vb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heasm66/unz/HEAD/UnZ/Program.vb -------------------------------------------------------------------------------- /UnZ/My Project/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "UnZ": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_linux-arm.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | True|2023-08-12T09:38:22.1305273Z; 8 | 9 | 10 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_win-arm.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | True|2023-08-12T09:40:30.5301587Z; 8 | 9 | 10 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_win-x86.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | True|2023-08-12T09:41:30.1488506Z; 8 | 9 | 10 | -------------------------------------------------------------------------------- /UnZ/UnZ.vbproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | UnZ 6 | net9.0 7 | 0.15 8 | 0.15 9 | 0.15 10 | On 11 | 2021-2025 Henrik Åsman 12 | 13 | 14 | 15 | build$([System.DateTime]::UtcNow.ToString("yyyyMMddHHmmss")) 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_linux-x64.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | True|2024-12-27T08:51:17.4155110Z||;True|2024-02-24T16:14:43.2717289+01:00||;True|2024-02-18T09:21:52.0532254+01:00||;True|2024-02-18T09:17:04.1617733+01:00||;True|2024-02-18T09:12:20.6618585+01:00||;True|2024-02-17T14:31:24.9990554+01:00||;True|2024-02-17T10:29:48.1125305+01:00||;True|2023-08-12T11:39:02.7875971+02:00||; 8 | 9 | 10 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_osx-x64.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | True|2024-12-27T08:51:39.3544206Z||;True|2024-02-24T16:14:56.4928178+01:00||;True|2024-02-18T09:22:02.3026651+01:00||;True|2024-02-18T09:16:52.4228904+01:00||;True|2024-02-18T09:16:30.6352748+01:00||;True|2024-02-18T09:12:32.3074030+01:00||;True|2024-02-17T14:31:10.2595244+01:00||;True|2024-02-17T10:34:36.6084063+01:00||;True|2023-08-12T11:39:46.9885688+02:00||; 8 | 9 | 10 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_osx-x64.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\SingleFile\osx-x64 10 | FileSystem 11 | net9.0 12 | osx-x64 13 | true 14 | true 15 | true 16 | true 17 | true 18 | True 19 | 20 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_linux-arm.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\SingleFile\linux-arm 10 | FileSystem 11 | net7.0 12 | linux-arm 13 | true 14 | true 15 | True 16 | True 17 | true 18 | True 19 | 20 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_linux-x64.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\SingleFile\linux-x64\ 10 | FileSystem 11 | net9.0 12 | linux-x64 13 | true 14 | true 15 | true 16 | true 17 | true 18 | True 19 | 20 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_win-arm.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\SingleFile\win-arm 10 | FileSystem 11 | net7.0 12 | win-arm 13 | true 14 | true 15 | True 16 | False 17 | True 18 | true 19 | True 20 | 21 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_win-x86.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\SingleFile\win-x86\ 10 | FileSystem 11 | net7.0 12 | win-x86 13 | true 14 | true 15 | True 16 | False 17 | True 18 | true 19 | True 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2024 Henrik Åsman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /UnZ.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34408.163 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "UnZ", "UnZ\UnZ.vbproj", "{220A6231-3804-4215-8E4B-D0EA6D74212A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {220A6231-3804-4215-8E4B-D0EA6D74212A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {220A6231-3804-4215-8E4B-D0EA6D74212A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {220A6231-3804-4215-8E4B-D0EA6D74212A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {220A6231-3804-4215-8E4B-D0EA6D74212A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {853C1D48-A3EC-4FD6-9A73-4CEEF1219FD4} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_win-x64.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\SingleFile\win-x64 10 | FileSystem 11 | net9.0 12 | win-x64 13 | true 14 | True 15 | true 16 | True 17 | True 18 | 19 | 20 | True 21 | True 22 | false 23 | False 24 | true 25 | True 26 | none 27 | False 28 | 29 | -------------------------------------------------------------------------------- /UnZ/My Project/PublishProfiles/SingleFile_win-x64.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | True|2024-12-27T08:51:52.4865502Z||;True|2024-12-27T09:19:12.0797492+01:00||;True|2024-12-27T08:12:12.9863150+01:00||;True|2024-12-27T08:10:11.7765304+01:00||;True|2024-12-27T08:03:59.0326980+01:00||;False|2024-12-27T08:03:21.2772670+01:00||;True|2024-12-27T07:53:01.6123940+01:00||;True|2024-12-27T07:51:28.8185147+01:00||;True|2024-12-27T06:52:47.6070631+01:00||;True|2024-12-27T06:42:20.2725429+01:00||;True|2024-12-27T03:55:16.0819019+01:00||;True|2024-12-27T03:47:12.6076071+01:00||;True|2024-12-26T20:53:35.5748924+01:00||;True|2024-12-26T20:43:22.5570398+01:00||;True|2024-12-26T20:41:45.8002950+01:00||;True|2024-12-26T20:33:03.4354634+01:00||;False|2024-12-26T20:32:31.5332382+01:00||;True|2024-12-26T18:57:53.5813255+01:00||;True|2024-12-26T15:50:54.4727259+01:00||;True|2024-12-26T15:45:46.2653357+01:00||;True|2024-12-26T15:43:05.7834664+01:00||;True|2024-12-26T13:22:45.2236130+01:00||;True|2024-12-26T11:24:26.1480575+01:00||;True|2024-12-26T09:21:58.0964023+01:00||;True|2024-12-26T09:20:05.3352525+01:00||;True|2024-12-26T09:16:14.2462088+01:00||;True|2024-12-26T09:11:52.4128920+01:00||;True|2024-12-26T08:56:22.1300934+01:00||;True|2024-12-26T08:35:53.2299583+01:00||;True|2024-12-25T06:26:45.8780575+01:00||;True|2024-12-25T06:25:44.6544713+01:00||;True|2024-12-20T13:17:15.7868000+01:00||;True|2024-12-19T14:39:24.1201388+01:00||;True|2024-12-18T13:47:53.9870604+01:00||;True|2024-12-17T12:20:05.7529422+01:00||;True|2024-12-17T12:11:58.8089560+01:00||;True|2024-12-17T10:27:50.9090503+01:00||;True|2024-12-17T10:19:59.5796666+01:00||;True|2024-12-17T10:14:11.4217939+01:00||;True|2024-12-17T10:11:53.3318672+01:00||;True|2024-12-17T10:09:05.2599160+01:00||;True|2024-12-17T10:05:08.6186962+01:00||;True|2024-12-17T10:01:59.0385609+01:00||;True|2024-12-17T09:59:05.1067914+01:00||;True|2024-12-17T09:25:22.7937271+01:00||;True|2024-12-17T09:20:29.8160540+01:00||;True|2024-12-17T09:16:47.2682230+01:00||;True|2024-12-17T08:16:10.8386149+01:00||;True|2024-12-15T09:32:32.4470573+01:00||;True|2024-12-15T09:27:35.4782578+01:00||;True|2024-12-10T15:55:31.5078502+01:00||;True|2024-12-07T12:02:34.6967002+01:00||;True|2024-12-07T12:01:31.4625497+01:00||;True|2024-12-07T11:46:56.5275886+01:00||;True|2024-12-06T14:50:40.3011207+01:00||;True|2024-12-06T14:48:11.4290180+01:00||;True|2024-12-06T13:25:45.8677318+01:00||;True|2024-12-06T13:22:32.5462269+01:00||;True|2024-12-06T13:17:40.9215984+01:00||;True|2024-12-06T13:16:35.1063331+01:00||;True|2024-12-06T13:15:07.9492852+01:00||;True|2024-12-06T13:12:50.3401719+01:00||;True|2024-12-05T08:31:36.2082402+01:00||;True|2024-12-05T07:36:58.0389067+01:00||;True|2024-12-05T07:36:35.6619649+01:00||;True|2024-12-04T08:53:16.3276684+01:00||;True|2024-12-04T08:11:31.0361257+01:00||;True|2024-12-04T08:00:07.4639879+01:00||;True|2024-12-03T16:37:16.7388382+01:00||;True|2024-12-03T15:43:52.9475433+01:00||;True|2024-12-03T15:43:19.9505058+01:00||;True|2024-12-03T15:04:31.1537494+01:00||;True|2024-12-03T14:40:33.5614978+01:00||;True|2024-11-23T16:51:02.1060393+01:00||;True|2024-03-18T15:53:04.8382989+01:00||;True|2024-03-12T12:52:33.1419683+01:00||;True|2024-03-12T09:02:22.3551887+01:00||;True|2024-03-12T08:59:00.3130443+01:00||;True|2024-02-24T16:14:27.8953195+01:00||;True|2024-02-24T09:33:38.6323408+01:00||;True|2024-02-23T13:04:29.5015225+01:00||;True|2024-02-23T13:03:32.3903558+01:00||;True|2024-02-23T13:01:13.5129772+01:00||;True|2024-02-23T08:27:42.6460141+01:00||;True|2024-02-23T08:20:34.8823595+01:00||;True|2024-02-21T15:27:14.4402429+01:00||;True|2024-02-20T16:21:23.5461268+01:00||;True|2024-02-20T16:19:42.4403823+01:00||;True|2024-02-20T16:17:17.4508600+01:00||;True|2024-02-20T08:46:46.5628888+01:00||;True|2024-02-20T08:43:44.6491700+01:00||;True|2024-02-20T08:09:59.2142112+01:00||;True|2024-02-19T16:06:38.4950584+01:00||;True|2024-02-19T14:57:58.4044922+01:00||;True|2024-02-19T14:57:45.3631395+01:00||;True|2024-02-19T14:34:55.1895340+01:00||;True|2024-02-19T14:24:06.1293018+01:00||;True|2024-02-19T09:19:40.8194348+01:00||;True|2024-02-19T09:03:34.1502722+01:00||;True|2024-02-19T08:41:14.0146620+01:00||; 8 | 9 | 10 | -------------------------------------------------------------------------------- /UnZ/MemoryMap.vb: -------------------------------------------------------------------------------- 1 | 'MIT License 2 | 3 | 'Copyright(c) 2021-2025 Henrik Åsman 4 | 5 | 'Permission Is hereby granted, free Of charge, to any person obtaining a copy 6 | 'of this software And associated documentation files (the "Software"), to deal 7 | 'in the Software without restriction, including without limitation the rights 8 | 'to use, copy, modify, merge, publish, distribute, sublicense, And/Or sell 9 | 'copies of the Software, And to permit persons to whom the Software Is 10 | 'furnished to do so, subject to the following conditions: 11 | 12 | 'The above copyright notice And this permission notice shall be included In all 13 | 'copies Or substantial portions of the Software. 14 | 15 | 'THE SOFTWARE Is PROVIDED "AS IS", WITHOUT WARRANTY Of ANY KIND, EXPRESS Or 16 | 'IMPLIED, INCLUDING BUT Not LIMITED To THE WARRANTIES Of MERCHANTABILITY, 17 | 'FITNESS FOR A PARTICULAR PURPOSE And NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | 'AUTHORS Or COPYRIGHT HOLDERS BE LIABLE For ANY CLAIM, DAMAGES Or OTHER 19 | 'LIABILITY, WHETHER In AN ACTION Of CONTRACT, TORT Or OTHERWISE, ARISING FROM, 20 | 'OUT OF Or IN CONNECTION WITH THE SOFTWARE Or THE USE Or OTHER DEALINGS IN THE 21 | 'SOFTWARE. 22 | 23 | Public Enum MemoryMapType 24 | MM_HEADER_TABLE 25 | MM_HEADER_EXT_TABLE 26 | MM_ABBREVIATION_STRINGS 27 | MM_ABBREVIATION_TABLE 28 | MM_PROPERTY_DEFAULTS_TABLE 29 | MM_OBJECT_TREE_TABLE 30 | MM_OBJECT_PROPERTIES_TABLES 31 | MM_GLOBAL_VARIABLES 32 | MM_TERMINATING_CHARS_TABLE 33 | MM_GRAMMAR_TABLE 34 | MM_GRAMMAR_TABLE_DATA 35 | MM_ACTION_TABLE 36 | MM_PREPOSITION_TABLE 37 | MM_PREPOSITION_TABLE_COUNT 38 | MM_PREACTION_TABLE 39 | MM_PREACTION_PARSING_TABLE 40 | MM_DICTIONARY 41 | MM_ZCODE 42 | MM_STATIC_STRINGS 43 | MM_CHRSET 44 | MM_IFID 45 | MM_UNIDENTIFIED_DATA 46 | MM_PADDING 47 | MM_WORD_FLAGS_TABLE 48 | MM_UNICODE_TABLE 49 | MM_MAIN_HEAP 50 | MM_AUX_LT_HEAP 51 | MM_PREDICATE_DATA 52 | MM_SCRATCH_AREA 53 | End Enum 54 | 55 | Public Class MemoryMapEntry 56 | Public Sub New(pName As String, pAddressStart As Integer, pAddressEnd As Integer, pType As MemoryMapType) 57 | name = pName 58 | addressStart = pAddressStart 59 | addressEnd = pAddressEnd 60 | type = pType 61 | End Sub 62 | 63 | Public name As String = "" 64 | Public addressStart As Integer = 0 65 | Public addressEnd As Integer = 0 66 | Public type As MemoryMapType = MemoryMapType.MM_UNIDENTIFIED_DATA 67 | Public startOfDynamic As Boolean = False 68 | Public startOfStatic As Boolean = False 69 | Public startOfHigh As Boolean = False 70 | 71 | 72 | Public ReadOnly Property SizeString As String 73 | Get 74 | Dim size As Integer = addressEnd - addressStart + 1 75 | If size = 1 Then Return "1 byte" 76 | Return size.ToString("#,##0 bytes") 77 | End Get 78 | End Property 79 | 80 | Public Sub PrintMemoryLabel() 81 | If startOfDynamic Then 82 | Console.WriteLine() 83 | Console.WriteLine("*****************************************************") 84 | Console.WriteLine("********** START OF DYNAMIC MEMORY 0x{0:X5} **********", addressStart) 85 | Console.WriteLine("*****************************************************") 86 | Console.WriteLine() 87 | End If 88 | If startOfStatic Then 89 | Console.WriteLine() 90 | Console.WriteLine("****************************************************") 91 | Console.WriteLine("********** START OF STATIC MEMORY 0x{0:X5} **********", addressStart) 92 | Console.WriteLine("****************************************************") 93 | Console.WriteLine() 94 | End If 95 | If startOfHigh Then 96 | Console.WriteLine() 97 | Console.WriteLine("**************************************************") 98 | Console.WriteLine("********** START OF HIGH MEMORY 0x{0:X5} **********", addressStart) 99 | Console.WriteLine("**************************************************") 100 | Console.WriteLine() 101 | End If 102 | End Sub 103 | End Class 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## UnZ 2 | 3 | ### Build native binaries 4 | 5 | - **MacOS arm64**: `dotnet publish -c Release -r osx-arm64 --self-contained true -p:PublishAot=true` 6 | - **MacOS intel**: `dotnet publish -c Release -r osx-x64 --self-contained true -p:PublishAot=true` 7 | - **Windows x64**: `dotnet publish -c Release -r win-x64 --self-contained true -p:PublishAot=true` 8 | - **Windows x86**: `dotnet publish -c Release -r win-x86 --self-contained true -p:PublishAot=true` 9 | - **Linux x64**: `dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishAot=true` 10 | - **Linux arm64**: `dotnet publish -c Release -r linux-arm64 --self-contained true -p:PublishAot=true` 11 | 12 | Precompiled binariers at: https://drive.google.com/drive/folders/1jl8Ym-6GzLiJgfdY8QORERw9Krvdk_-k 13 | ``` 14 | UnZ 0.17 (15th October 2025, in development) by Henrik Åsman, (c) 2021-2025 15 | Usage: unz [option]... [file] 16 | Unpack Z-machine file format information. 17 | 18 | -a Show the abbreviation sections. 19 | -d Show the dictionary section. 20 | -f Show all sections (default). 21 | -g Show the grammar section. 22 | --gametext Output only a 'gametext.txt' format of all text in the file. 23 | -h, --help, /? Show this help. 24 | --hexdump Show raw hexdump before each section. 25 | --hide Don't show the abbreviation insertion points in the strings. 26 | -i Show the header section. 27 | --invisiclues Show Object Tree in InvisiClues format. 28 | -m Show the memory map. 29 | -o Show the objects sections. 30 | -s Show the strings section. 31 | --syntax 0/txd Use TXD default syntax for the z-code decompilation. (default) 32 | 1/inform Use Inform syntax for the z-code decompilation. (txd -a) 33 | 2/ZAP Use ZAP syntax for the z-code decompilation. 34 | 3/pseudo Use pseudo-code (Informish) syntax for the z-code decompilation. 35 | -u Show the unidentified sections. 36 | -v Show the variable section. 37 | -x Show miscellaneous other sections. 38 | -z Show the z-code section. 39 | -z Show the single decompiled z-code routine at 40 | --zverbose Show detailed breakdown of z-code 41 | 42 | Report bugs/suggestions to: heasm66@gmail.com 43 | UnZ homepage: https://github.com/heasm66/unz 44 | 45 | 46 | Changelog: 47 | 0.17 2025-xx-xx 48 | --------------- 49 | * Bug: Adjust for that Zilf 0.9 can under some circumstances 50 | produce less than 96 abbreviations (FSTR?DUMMY) 51 | * Guards for minimal file with no objects and no strings 52 | * Bug: Identify end of routines correctly, when QUIT 53 | is last before start of high strings 54 | * Bug: highest global and used globals computed wrong 55 | * Bug: improve logic dictword/packed address (ambiguity) 56 | in decoding properties on objects 57 | 58 | 0.16 2025-07-10 59 | --------------- 60 | * Bug: stack.peek() should only be in if-statements 61 | * Bug: print_paddr handled variables wrong 62 | * Bug: Small strings area can make z-decoding go out of bounds 63 | 64 | 0.15 2025-07-04 65 | --------------- 66 | * Bug: Hexdump of EXTOP showed wrong byte-value 67 | * Bug: XCALL & IXCALL showed wrong type for operand 5- 68 | * Bug: @buffer_screen should have E_STORE 69 | * Bug: Store-var should be hex for syntax 0 70 | * Verbose description of opcodes (--zverbose) 71 | * Pseudo-code, Inform-ish syntax (syntax 3) 72 | 73 | 0.14 2025-06-26 74 | --------------- 75 | * Bugfixes and refactoring 76 | * Fix GetBuildDate 77 | * Fix to illegal parameter use of WINGET in Zork0_242 78 | * Identify zork1-r5-sXXXXXX.z1 and zork1-r20-sXXXXXX.z3 as Zilch 79 | * Handle Inform5-files with no prepositions (Scott Adams) 80 | * Handle Zilch/Zilf where there are no ACTIONS (ziptest) 81 | * Allow split chunks of z-code (Bureaucracy) 82 | 83 | 0.13 2024-12-27 84 | --------------- 85 | * Fixed bug that couldn't handle "no-verb" with 0 number_of_grammar_lines 86 | in Inform_GV2. 87 | * Inform6: Support for grammar version 3. 88 | * Support for unicode translation table. 89 | * Identify old compiled files right as Zilch(old Infocom files with oddly formed serials). 90 | * Accept files with no abbreviation tables. 91 | * Accept files with no objects. 92 | * Print object tree, special output for InvisiClues-files. 93 | * Dialog: Identify memory areas for heaps, predicates and scratch area. 94 | * Dialog: Mark data, that fills out so static mem - global start 95 | always is at least 480 bytes, as padding. 96 | 97 | 0.12 2024-02-24 98 | --------------- 99 | * Call without options or file prints help (same as -h). 100 | * Cosmetic changes to printing in the objects section. 101 | * List calls from property, action and preaction/parsing in 102 | z-code routine header. 103 | * List possible startingpoint for arrays in "undentified data", 104 | collected from opcodes loadb, loadw, storeb, storew and globals. 105 | 106 | 0.11 2024-02-18 107 | --------------- 108 | * Minor bug fixes and error handling. 109 | * Handle corrupt adjective table (Curses_r7) for Inform5_ver1 grammar. 110 | 111 | 0.10 2024-02-17 112 | --------------- 113 | * Initial commit. 114 | ``` 115 | 116 | -------------------------------------------------------------------------------- /UnZ/Helper.vb: -------------------------------------------------------------------------------- 1 | 'MIT License 2 | 3 | 'Copyright(c) 2021-2025 Henrik Åsman 4 | 5 | 'Permission Is hereby granted, free Of charge, to any person obtaining a copy 6 | 'of this software And associated documentation files (the "Software"), to deal 7 | 'in the Software without restriction, including without limitation the rights 8 | 'to use, copy, modify, merge, publish, distribute, sublicense, And/Or sell 9 | 'copies of the Software, And to permit persons to whom the Software Is 10 | 'furnished to do so, subject to the following conditions: 11 | 12 | 'The above copyright notice And this permission notice shall be included In all 13 | 'copies Or substantial portions of the Software. 14 | 15 | 'THE SOFTWARE Is PROVIDED "AS IS", WITHOUT WARRANTY Of ANY KIND, EXPRESS Or 16 | 'IMPLIED, INCLUDING BUT Not LIMITED To THE WARRANTIES Of MERCHANTABILITY, 17 | 'FITNESS FOR A PARTICULAR PURPOSE And NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | 'AUTHORS Or COPYRIGHT HOLDERS BE LIABLE For ANY CLAIM, DAMAGES Or OTHER 19 | 'LIABILITY, WHETHER In AN ACTION Of CONTRACT, TORT Or OTHERWISE, ARISING FROM, 20 | 'OUT OF Or IN CONNECTION WITH THE SOFTWARE Or THE USE Or OTHER DEALINGS IN THE 21 | 'SOFTWARE. 22 | 23 | Imports System.Formats 24 | Imports System.Globalization 25 | Imports System.IO 26 | Imports System.Net.Http 27 | Imports System.Reflection 28 | 29 | Public Enum EnumCompilerSource 30 | ZILCH 31 | ZILF 32 | INFORM5 33 | INFORM6 34 | DIALOG 35 | UNKNOWN 36 | End Enum 37 | 38 | Public Enum EnumGrammarVer 39 | VERSION_1 = 1 40 | VERSION_2 = 2 41 | VERSION_3 = 3 42 | UNKNOWN = 0 43 | End Enum 44 | Public Class Helper 45 | Public Shared Property UnicodeTranslationTableAddr As Integer = 0 46 | 47 | Public Shared Function GetAdressFromWord(byteGame() As Byte, index As Integer) As Integer 48 | Return byteGame(index) * 256 + byteGame(index + 1) 49 | End Function 50 | 51 | Public Shared Function GetAdressFromPacked(byteGame() As Byte, index As Integer, isRoutine As Boolean) As Integer 52 | Dim byteAddress As Integer = GetAdressFromWord(byteGame, index) 53 | Return UnpackAddress(byteAddress, byteGame, isRoutine) 54 | End Function 55 | 56 | Public Shared Function UnpackAddress(packedAddress As Integer, byteGame() As Byte, isRoutine As Boolean) As Integer 57 | Dim zVersion As Integer = byteGame(0) 58 | Dim offset As Integer = GetAdressFromWord(byteGame, &H28) 59 | If Not isRoutine Then offset = GetAdressFromWord(byteGame, &H2A) 60 | Select Case zVersion 61 | Case 1, 2, 3 62 | Return 2 * packedAddress 63 | Case 4, 5 64 | Return 4 * packedAddress 65 | Case 6, 7 66 | Return 4 * packedAddress + 8 * offset 67 | Case 8 68 | Return 8 * packedAddress 69 | Case Else 70 | Return 2 * packedAddress 71 | End Select 72 | End Function 73 | 74 | Public Shared Function GetNextValidPackedAddress(byteGame() As Byte, address As Integer) As Integer 75 | Dim Zversion As Integer = byteGame(0) 76 | Dim scaler As Integer = 2 77 | Select Case Zversion 78 | Case 4, 5, 6, 7 79 | scaler = 4 80 | Case 8 81 | scaler = 8 82 | End Select 83 | 'Dim offset As Integer = GetAdressFromWord(byteGame, &H28) 84 | 'If Not IsRoutine Then offset = GetAdressFromWord(byteGame, &H2A) 85 | 'offset = offset * 8 86 | Return CInt(Math.Truncate((address + scaler - 1) / scaler) * scaler) ' - offset 87 | End Function 88 | 89 | Public Shared Function ExtractZString(byteGame() As Byte, piStringAddress As Integer, sAbbreviations() As String, pAlphabet() As String, Optional pbHighlightAbbrevs As Boolean = False) As String 90 | Dim iCounter As Integer = 0 91 | Dim bLastW As Boolean 92 | Dim iWord As Integer 93 | Dim iAlpabeth As Integer = 0 94 | Dim sRet As String = "" 95 | Dim iAbbrevTable As Integer = -1 96 | Dim iZSCIIEscape As Integer = -1 97 | Dim iZSCIIEscapeCount As Integer = -1 98 | Dim Zversion As Integer = byteGame(0) 99 | Dim shiftLock As Integer = 0 100 | 101 | Do 102 | iWord = byteGame(piStringAddress + iCounter) * 256 + byteGame(piStringAddress + iCounter + 1) 103 | bLastW = CBool(iWord And 32768) 104 | For i As Integer = 2 To 0 Step -1 105 | Dim iZChar As Integer = CInt((iWord And CInt(((32 ^ i) * 31))) / (32 ^ i)) 106 | If iAbbrevTable > -1 Then 107 | ' Insert abbreviation 108 | If pbHighlightAbbrevs Then 109 | sRet = sRet & "{" & sAbbreviations((iAbbrevTable - 1) * 32 + iZChar) & "}" 110 | Else 111 | sRet &= sAbbreviations((iAbbrevTable - 1) * 32 + iZChar) 112 | End If 113 | iAbbrevTable = -1 114 | ElseIf iZSCIIEscapeCount <> -1 Then 115 | ' Insert ZSCII? 116 | iZSCIIEscapeCount += 1 117 | If iZSCIIEscapeCount = 1 Then 118 | iZSCIIEscape = iZChar 119 | ElseIf iZSCIIEscapeCount = 2 Then 120 | iZSCIIEscapeCount = -1 121 | iZSCIIEscape = 32 * iZSCIIEscape + iZChar 122 | If iZSCIIEscape = 0 Then 123 | ' NULL 124 | ElseIf iZSCIIEscape = 9 Then 125 | ' Tab for v6, converted to space 126 | sRet &= " " 127 | ElseIf iZSCIIEscape = 11 Then 128 | ' Sentence space for v6, converted to space 129 | sRet &= " " 130 | ElseIf iZSCIIEscape = 13 Then 131 | sRet &= "^" 132 | ElseIf iZSCIIEscape >= 32 And iZSCIIEscape <= 126 Then 133 | ' Standard ASCII, double-quote conerts to tilde 134 | sRet &= " !~#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~".Substring(iZSCIIEscape - 32, 1) 135 | ElseIf iZSCIIEscape >= 155 And iZSCIIEscape <= 251 Then 136 | ' Extra chars, unicode 137 | If Not UnicodeTranslationTableAddr > 0 Then 138 | ' Standard table 139 | sRet &= "äöüÄÖÜß»«ëïÿËÏáéíóúýÁÉÍÓÚÝàèìòùÀÈÌÒÙâêîôûÂÊÎÔÛåÅøØãñõÃÑÕæÆçÇþðÞУœŒ¡¿????????????????????????????".Substring(iZSCIIEscape - 155, 1) 140 | Else 141 | ' Use unicode translation table 142 | Dim unicodeTableLen As Integer = byteGame(UnicodeTranslationTableAddr) 143 | If ((iZSCIIEscape - 155) + 1) > unicodeTableLen Then 144 | sRet &= "?" 145 | Else 146 | Dim unicodeVal As Integer = Helper.GetAdressFromWord(byteGame, UnicodeTranslationTableAddr + (iZSCIIEscape - 155) * 2 + 1) 147 | sRet &= Strings.ChrW(unicodeVal) 148 | End If 149 | End If 150 | Else 151 | sRet &= "?" 152 | End If 153 | End If 154 | ElseIf Zversion = 1 And iZChar = 1 Then 155 | sRet &= "^" 156 | iAlpabeth = shiftLock 157 | ElseIf Zversion = 2 And iZChar = 1 Then 158 | iAbbrevTable = iZChar 159 | iAlpabeth = shiftLock 160 | ElseIf Zversion < 3 And iZChar = 2 Then 161 | iAlpabeth += 1 162 | If iAlpabeth > 2 Then iAlpabeth = 0 163 | ElseIf Zversion < 3 And iZChar = 3 Then 164 | iAlpabeth -= 1 165 | If iAlpabeth < 0 Then iAlpabeth = 2 166 | ElseIf Zversion < 3 And iZChar = 4 Then 167 | iAlpabeth += 1 168 | If iAlpabeth > 2 Then iAlpabeth = 0 169 | shiftLock = iAlpabeth 170 | ElseIf Zversion < 3 And iZChar = 5 Then 171 | iAlpabeth -= 1 172 | If iAlpabeth < 0 Then iAlpabeth = 2 173 | shiftLock = iAlpabeth 174 | ElseIf iZChar = 4 Then 175 | iAlpabeth = 1 176 | ElseIf iZChar = 5 Then 177 | iAlpabeth = 2 178 | ElseIf iZChar = 0 Then 179 | sRet &= " " 180 | iAlpabeth = shiftLock 181 | ElseIf iZChar < 6 Then 182 | ' Insert abbreviation 183 | iAbbrevTable = iZChar 184 | iAlpabeth = shiftLock 185 | ElseIf iZChar = 6 And iAlpabeth = 2 Then 186 | ' Start ZSCII sequence 187 | iZSCIIEscapeCount += 1 188 | iAlpabeth = shiftLock 189 | Else 190 | sRet &= pAlphabet(iAlpabeth).Substring(iZChar, 1) 191 | iAlpabeth = shiftLock 192 | End If 193 | Next 194 | iCounter += 2 195 | Loop Until bLastW 196 | 197 | Return sRet 198 | End Function 199 | 200 | Public Shared Function GetBuildDateUtc(ByVal assembly As Assembly) As DateTime 201 | Const BuildVersionMetadataPrefix As String = "+build" 202 | Dim attribute = assembly.GetCustomAttribute(Of AssemblyInformationalVersionAttribute)() 203 | Dim result As DateTime = Nothing 204 | 205 | If attribute?.InformationalVersion IsNot Nothing Then 206 | Dim value As String = attribute.InformationalVersion 207 | Dim index As Integer = value.IndexOf(BuildVersionMetadataPrefix) 208 | 209 | If index > 0 Then 210 | value = value.Substring(index + BuildVersionMetadataPrefix.Length) 211 | 212 | If DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None, result) Then 213 | Return result 214 | End If 215 | End If 216 | End If 217 | 218 | Return Now() 219 | End Function 220 | End Class 221 | 222 | Public Class StringData 223 | Public name As String = "" 224 | Public number As Integer = 0 225 | Public text As String = "" 226 | Public textWithAbbrevs As String = "" 227 | Public entryPoint As Integer = 0 228 | Public endPoint As Integer = 0 229 | Public entryPointPacked As Integer = 0 230 | Public ReadOnly Property GetText(showAbbrevsInsertion As Boolean) As String 231 | Get 232 | If showAbbrevsInsertion Then Return textWithAbbrevs Else Return text 233 | End Get 234 | End Property 235 | End Class 236 | 237 | Public Class RoutineData 238 | Public name As String = "" 239 | Public entryPoint As Integer = 0 240 | Public endPoint As Integer = 0 241 | Public entryPointPacked As Integer = 0 242 | Public callsFrom As New List(Of String) 243 | End Class 244 | 245 | Public Class CallsFromTo 246 | Public fromAddress As Integer 247 | Public toAddress As Integer 248 | End Class 249 | Public Class InlineString 250 | Public text As String = "" 251 | Public size As Integer = 0 252 | End Class 253 | 254 | Public Class DictionaryEntry 255 | Public dictWord As String = "" 256 | Public dictAddress As Integer = 0 257 | Public Flags As Integer = 0 258 | Public V1 As Integer = 0 259 | Public V2 As Integer = 0 260 | Public VerbNum As Integer = 0 261 | Public AdjNum As Integer = 0 262 | Public PrepNum As Integer = 0 263 | Public DirNum As Integer = 0 264 | Public Byte6ToLast As Integer = 0 265 | Public Byte5ToLast As Integer = 0 266 | Public Byte4ToLast As Integer = 0 267 | Public Byte3ToLast As Integer = 0 268 | Public Byte2ToLast As Integer = 0 269 | Public Byte1ToLast As Integer = 0 270 | Public v2_ClassificationNumber As Integer = 0 271 | Public v2_SemanticStuff As Integer = 0 272 | Public v2_WordFlags As Integer = 0 273 | End Class 274 | 275 | Public Class DictionaryEntries 276 | Inherits List(Of DictionaryEntry) 277 | 278 | Public WordSize As Integer = 0 279 | Public v1_CompactVocabulary As Boolean = False 280 | Public v2_OneBytePartsOfSpeech As Boolean = False 281 | Public v2_WordFlagsInTable As Boolean = True 282 | Public v2_PartsOfSpeech As New Dictionary(Of Integer, String) 283 | Public v2_VerbAddresses As List(Of Integer) 284 | Public v2_VerbWord As Integer = 0 285 | Public v2_NounWord As Integer = 0 286 | Public v2_AdjWord As Integer = 0 287 | Public v2_AdvWord As Integer = 0 288 | Public v2_QuantWord As Integer = 0 289 | Public v2_MiscWord As Integer = 0 290 | Public v2_CommaWord As Integer = 0 291 | Public v2_ParticleWord As Integer = 0 292 | Public v2_PrepWord As Integer = 0 293 | Public v2_ToBeWord As Integer = 0 294 | Public v2_ApostrWord As Integer = 0 295 | Public v2_OfWord As Integer = 0 296 | Public v2_ArticleWord As Integer = 0 297 | Public v2_QuoteWord As Integer = 0 298 | Public v2_EOIWord As Integer = 0 299 | Public v2_DirWord As Integer = 0 300 | Public v2_CanDoWord As Integer = 0 301 | Public v2_QWord As Integer = 0 302 | Public v2_AskWord As Integer = 0 303 | 304 | Public ReadOnly Property DirectionCount() As Integer 305 | Get 306 | Dim oList As New List(Of Integer) 307 | For Each oEntry As DictionaryEntry In Me 308 | If oEntry.DirNum > 0 AndAlso Not oList.Contains(oEntry.DirNum) Then oList.Add(oEntry.DirNum) 309 | Next 310 | Return oList.Count 311 | End Get 312 | End Property 313 | 314 | Public ReadOnly Property PrepositionCountUnique() As Integer 315 | Get 316 | Dim oList As New List(Of Integer) 317 | For Each oEntry As DictionaryEntry In Me 318 | If oEntry.PrepNum > 0 AndAlso Not oList.Contains(oEntry.PrepNum) Then oList.Add(oEntry.PrepNum) 319 | Next 320 | Return oList.Count 321 | End Get 322 | End Property 323 | 324 | Public ReadOnly Property PrepositionCountTotal() As Integer 325 | Get 326 | Dim count As Integer = 0 327 | For Each oEntry As DictionaryEntry In Me 328 | If (oEntry.Flags And 8) = 8 Then 329 | count += 1 330 | End If 331 | Next 332 | Return count 333 | End Get 334 | End Property 335 | 336 | Private _adjectiveCount As Integer = -1 337 | Public ReadOnly Property AdjectiveCount() As Integer 338 | ' Only for ZIL, version 1-3 339 | Get 340 | If _adjectiveCount > -1 Then Return _adjectiveCount 341 | Dim oList As New List(Of Integer) 342 | For Each oEntry As DictionaryEntry In Me 343 | If oEntry.AdjNum > 0 AndAlso Not oList.Contains(oEntry.AdjNum) Then oList.Add(oEntry.AdjNum) 344 | Next 345 | _adjectiveCount = oList.Count 346 | Return _adjectiveCount 347 | End Get 348 | End Property 349 | 350 | Public Function GetVerb(piVerbNum As Integer) As DictionaryEntries 351 | Dim listRet As New DictionaryEntries 352 | For Each dictEntry As DictionaryEntry In Me 353 | If dictEntry.VerbNum = piVerbNum Then listRet.Add(dictEntry) 354 | Next 355 | Return listRet 356 | End Function 357 | 358 | Public Function GetLowestVerbNum() As Integer 359 | Dim iLowestVerbNum = 256 360 | For Each dictEntry As DictionaryEntry In Me 361 | If dictEntry.VerbNum > 0 And dictEntry.VerbNum < iLowestVerbNum Then iLowestVerbNum = dictEntry.VerbNum 362 | Next 363 | Return iLowestVerbNum 364 | End Function 365 | 366 | Public Function GetAdjective(piAdjNum As Integer) As DictionaryEntries 367 | Dim listRet As New DictionaryEntries 368 | For Each dictEntry As DictionaryEntry In Me 369 | If dictEntry.AdjNum = piAdjNum Then listRet.Add(dictEntry) 370 | Next 371 | Return listRet 372 | End Function 373 | 374 | Public Function GetDirection(piDirNum As Integer) As DictionaryEntries 375 | Dim listRet As New DictionaryEntries 376 | For Each dictEntry As DictionaryEntry In Me 377 | If dictEntry.DirNum = piDirNum Then listRet.Add(dictEntry) 378 | Next 379 | Return listRet 380 | End Function 381 | 382 | Public Function GetPreposition(piPrepNum As Integer) As DictionaryEntries 383 | Dim listRet As New DictionaryEntries 384 | For Each dictEntry As DictionaryEntry In Me 385 | If dictEntry.PrepNum = piPrepNum Then listRet.Add(dictEntry) 386 | Next 387 | Return listRet 388 | End Function 389 | 390 | Public Function GetEntryAtAddress(piAddress As Integer) As DictionaryEntry 391 | For Each dictEntry As DictionaryEntry In Me 392 | If dictEntry.dictAddress = piAddress Then Return dictEntry 393 | Next 394 | Return Nothing 395 | End Function 396 | End Class 397 | 398 | Public Class ObjectData 399 | Public Id As Integer = -1 400 | Public Description As String = "" 401 | Public ParentId As Integer = 0 402 | Public NextId As Integer = 0 403 | Public ChildId As Integer = 0 404 | Public Property4Strings As New List(Of String) 405 | Public Property8Strings As New List(Of String) 406 | End Class 407 | -------------------------------------------------------------------------------- /UnZ/PropertyAnalyser.vb: -------------------------------------------------------------------------------- 1 | 'MIT License 2 | 3 | 'Copyright(c) 2021-2025 Henrik Åsman 4 | 5 | 'Permission Is hereby granted, free Of charge, to any person obtaining a copy 6 | 'of this software And associated documentation files (the "Software"), to deal 7 | 'in the Software without restriction, including without limitation the rights 8 | 'to use, copy, modify, merge, publish, distribute, sublicense, And/Or sell 9 | 'copies of the Software, And to permit persons to whom the Software Is 10 | 'furnished to do so, subject to the following conditions: 11 | 12 | 'The above copyright notice And this permission notice shall be included In all 13 | 'copies Or substantial portions of the Software. 14 | 15 | 'THE SOFTWARE Is PROVIDED "AS IS", WITHOUT WARRANTY Of ANY KIND, EXPRESS Or 16 | 'IMPLIED, INCLUDING BUT Not LIMITED To THE WARRANTIES Of MERCHANTABILITY, 17 | 'FITNESS FOR A PARTICULAR PURPOSE And NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | 'AUTHORS Or COPYRIGHT HOLDERS BE LIABLE For ANY CLAIM, DAMAGES Or OTHER 19 | 'LIABILITY, WHETHER In AN ACTION Of CONTRACT, TORT Or OTHERWISE, ARISING FROM, 20 | 'OUT OF Or IN CONNECTION WITH THE SOFTWARE Or THE USE Or OTHER DEALINGS IN THE 21 | 'SOFTWARE. 22 | 23 | Public Enum PropertyType 24 | ZIL_DIRECTION 25 | ZIL_ADJECTIVE 26 | ZIL_THINGS 27 | ZIL_PSEUDO 28 | ZIL_GLOBAL 29 | ZIL_ACTION 30 | ZIL_HIGH_STRING 31 | ZIL_STRING 32 | ZIL_VALUE 33 | ZIL_TABLE 34 | ZIL_UNKNOWN 35 | SYNONYM 36 | UNINITIATED 37 | UNUSED 38 | AMBIGUITY 39 | End Enum 40 | 41 | Public Class PropertyAnalyser 42 | Public addressObjectTreeStart As Integer = 0 43 | Public addressObjectTreeEnd As Integer = 0 44 | Public objectTreeEntryLength As Integer = 0 45 | Public objectCount As Integer = 0 46 | Public addressObjectPropTableStart As Integer = 0 47 | Public addressObjectPropTableEnd As Integer = 0 48 | Public propertyNumberMax As Integer = 0 49 | Public propertyNumberMin As Integer = 0 50 | 51 | Private ReadOnly properties As New List(Of PropertyEntry) 52 | Private compilerSource As EnumCompilerSource 53 | Private ZVersion As Integer = 0 54 | 55 | Private Class PropertyData 56 | Public parentObject As Integer 57 | Public data As New List(Of Byte) 58 | End Class 59 | 60 | Private Class PropertyEntry 61 | Public number As Integer = 0 62 | Public data As New List(Of PropertyData) 63 | 64 | Private _type As PropertyType = PropertyType.UNINITIATED 65 | 66 | Public ReadOnly Property PropertyType As PropertyType 67 | Get 68 | Return _type 69 | End Get 70 | End Property 71 | 72 | Private ReadOnly _ambiguityTypeList As New List(Of PropertyType) 73 | Public ReadOnly Property AmbiguityTypes() As List(Of PropertyType) 74 | Get 75 | Return _ambiguityTypeList 76 | End Get 77 | End Property 78 | 79 | Public Sub AddPropertyType(pPropertyType As PropertyType) 80 | If _type = PropertyType.UNINITIATED Then 81 | _type = pPropertyType 82 | Else 83 | _type = PropertyType.AMBIGUITY 84 | End If 85 | _ambiguityTypeList.Add(pPropertyType) 86 | End Sub 87 | End Class 88 | 89 | Private Sub AddProperty(pObjectNumber As Integer, pPropertyNumber As Integer, pData As List(Of Byte)) 90 | Dim entry As PropertyEntry = properties.Find(Function(x) x.number = pPropertyNumber) 91 | If entry Is Nothing Then 92 | entry = New PropertyEntry 93 | properties.Add(entry) 94 | End If 95 | 96 | entry.number = pPropertyNumber 97 | Dim propertyData = New PropertyData With {.parentObject = pObjectNumber, .data = pData} 98 | entry.data.Add(propertyData) 99 | End Sub 100 | 101 | Public Sub Init(pStoryData() As Byte, pAddrObjectTreeStart As Integer, pZVersion As Integer, pCompilerSource As EnumCompilerSource) 102 | ' Loop through all properties tables and collect them according to property number for later analysis. 103 | 104 | compilerSource = pCompilerSource 105 | ZVersion = pZVersion 106 | 107 | objectTreeEntryLength = 14 108 | If pZVersion <= 3 Then objectTreeEntryLength = 9 109 | 110 | ' Loop through all pointers to property data to find lowest (=start of property data tables) 111 | Dim lowestPropAddress As Integer = Helper.GetAdressFromWord(pStoryData, pAddrObjectTreeStart + objectTreeEntryLength - 2) 112 | If lowestPropAddress > Helper.GetAdressFromWord(pStoryData, 14) Then Exit Sub ' Address MUST be in dynamic memory, There are problably no objects 113 | Dim i As Integer = 1 114 | Do 115 | Dim currentPropAddress As Integer = Helper.GetAdressFromWord(pStoryData, pAddrObjectTreeStart + objectTreeEntryLength * i - 2) 116 | If currentPropAddress < pAddrObjectTreeStart + objectTreeEntryLength * i Then Exit Do ' Ill formed table 117 | If currentPropAddress < lowestPropAddress Then lowestPropAddress = currentPropAddress 118 | i += 1 119 | Loop Until pAddrObjectTreeStart + objectTreeEntryLength * i - 2 >= lowestPropAddress 120 | objectCount = i - 1 121 | ' Object properties tables follow directly after so the address of the first objects properties divided by the entry-length gives the number of objects 122 | 'objectCount = ((pStoryData(pAddrObjectTreeStart + objectTreeEntryLength - 2) * 256 + pStoryData(pAddrObjectTreeStart + objectTreeEntryLength - 1)) - pAddrObjectTreeStart) / objectTreeEntryLength 123 | addressObjectTreeEnd = pAddrObjectTreeStart + objectCount * objectTreeEntryLength - 1 124 | 'addressObjectPropTableStart = addressObjectTreeEnd + 1 125 | addressObjectPropTableStart = lowestPropAddress 126 | 127 | Dim iAddrObjectProperties As Integer = 65536 128 | Dim iAddrProperties As Integer 129 | For i = 0 To objectCount - 1 130 | Dim iObject As Integer = i + 1 131 | iAddrProperties = pStoryData(pAddrObjectTreeStart + iObject * objectTreeEntryLength - 2) * 256 + pStoryData(pAddrObjectTreeStart + iObject * objectTreeEntryLength - 1) 132 | If iAddrProperties < iAddrObjectProperties Then iAddrObjectProperties = iAddrProperties 133 | Dim iPropDescLen As Integer = pStoryData(iAddrProperties) 134 | Dim iTmpProp As Integer = iAddrProperties + 2 * iPropDescLen + 1 135 | If iPropDescLen > 0 Then 136 | Do While pStoryData(iTmpProp) <> 0 137 | Dim iPropNum As Integer 138 | Dim iPropSize As Integer 139 | Dim iPropStart As Integer = iTmpProp + 1 140 | If pZVersion <= 3 Then 141 | iPropNum = (pStoryData(iTmpProp) And &H1F) 142 | iPropSize = 1 + (pStoryData(iTmpProp) And 224) \ 32 143 | Else 144 | iPropNum = (pStoryData(iTmpProp) And &H3F) 145 | If (pStoryData(iTmpProp) And &H80) = &H80 Then 146 | iPropSize = (pStoryData(iTmpProp + 1) And &H3F) 147 | If iPropSize = 0 Then iPropSize = &H40 148 | iPropStart += 1 149 | Else 150 | If (pStoryData(iTmpProp) And 64) = 64 Then iPropSize = 2 Else iPropSize = 1 151 | End If 152 | End If 153 | 154 | Dim propData As New List(Of Byte) 155 | For j As Integer = 0 To iPropSize + iPropStart - iTmpProp - 1 156 | If j >= (iPropStart - iTmpProp) Then propData.Add(pStoryData(iTmpProp + j)) 157 | Next 158 | iTmpProp = iPropStart + iPropSize 159 | Me.AddProperty(iObject, iPropNum, propData) 160 | If iPropNum < propertyNumberMin Then propertyNumberMin = iPropNum 161 | If iPropNum > propertyNumberMax Then propertyNumberMax = iPropNum 162 | Loop 163 | End If 164 | If iTmpProp > addressObjectPropTableEnd Then addressObjectPropTableEnd = iTmpProp 165 | Next 166 | End Sub 167 | 168 | Private dictionary As DictionaryEntries = Nothing 169 | Private routineList As List(Of RoutineData) = Nothing 170 | Private stringList As List(Of StringData) = Nothing 171 | Private MemoryMap As List(Of MemoryMapEntry) = Nothing 172 | 173 | Public Sub Analyse(pDictionary As DictionaryEntries, pStringList As List(Of StringData), pRoutineList As List(Of RoutineData), pMemoryMap As List(Of MemoryMapEntry)) 174 | dictionary = pDictionary 175 | routineList = pRoutineList 176 | stringList = pStringList 177 | MemoryMap = pMemoryMap 178 | 179 | For Each propEntry As PropertyEntry In properties 180 | If IdentifySynonym(propEntry) Then propEntry.AddPropertyType(PropertyType.SYNONYM) 181 | 182 | If {EnumCompilerSource.ZILCH, EnumCompilerSource.ZILF}.Contains(compilerSource) Then 183 | If IdentifyZILDirection(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_DIRECTION) 184 | If IdentifyZILAction(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_ACTION) 185 | If IdentifyZILAdjective(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_ADJECTIVE) 186 | If IdentifyZILHighString(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_HIGH_STRING) 187 | If IdentifyZILPseudo(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_PSEUDO) 188 | If IdentifyZILGlobal(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_GLOBAL) 189 | If IdentifyZILValue(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_VALUE) 190 | If IdentifyZILTable(propEntry) Then propEntry.AddPropertyType(PropertyType.ZIL_TABLE) 191 | If propEntry.PropertyType = PropertyType.UNINITIATED Then propEntry.AddPropertyType(PropertyType.ZIL_UNKNOWN) 192 | ElseIf {EnumCompilerSource.INFORM5, EnumCompilerSource.INFORM6}.Contains(compilerSource) Then 193 | Else 194 | 195 | End If 196 | Next 197 | End Sub 198 | 199 | Private Function IdentifyZILDirection(pPropEntry As PropertyEntry) As Boolean 200 | If dictionary.GetDirection(pPropEntry.number).Count = 0 Then 201 | Return False 202 | Else 203 | For Each oPropData As PropertyData In pPropEntry.data 204 | If oPropData.data.Count < 2 And ZVersion > 3 Then Return False 205 | If oPropData.data.Count > 6 And ZVersion > 3 Then Return False 206 | If oPropData.data.Count > 5 And ZVersion < 4 Then Return False 207 | Next 208 | End If 209 | Return True 210 | End Function 211 | 212 | Private Function IdentifySynonym(pPropEntry As PropertyEntry) As Boolean 213 | ' Length mod 2 = 0, returns true if all points to words in the dictionary, otherwise false 214 | For Each oPropData As PropertyData In pPropEntry.data 215 | If Not (oPropData.data.Count Mod 2) = 0 Then Return False 216 | For i As Integer = 0 To oPropData.data.Count - 2 Step 2 217 | If dictionary.GetEntryAtAddress(oPropData.data(i) * 256 + oPropData.data(i + 1)) Is Nothing Then Return False 218 | Next 219 | Next 220 | Return True 221 | End Function 222 | 223 | Private Function IdentifyZILAdjective(pPropEntry As PropertyEntry) As Boolean 224 | ' Version 1-3: List of adjective numbers (from dictionary) 225 | ' Adjectives are numbered from 255 downward 226 | ' Version 4- : List of dictionary words, all with wordtype = adjective 227 | If ZVersion < 4 Then 228 | For Each oPropData As PropertyData In pPropEntry.data 229 | For i As Integer = 0 To oPropData.data.Count - 1 230 | If oPropData.data(i) = 0 Then Return False 231 | If oPropData.data(i) < (256 - dictionary.AdjectiveCount) Then Return False 232 | Next 233 | Next 234 | Return True 235 | Else 236 | For Each oPropData As PropertyData In pPropEntry.data 237 | If Not (oPropData.data.Count Mod 2) = 0 Then Return False 238 | For i As Integer = 0 To oPropData.data.Count - 2 Step 2 239 | Dim oWordEntry As DictionaryEntry = dictionary.GetEntryAtAddress(oPropData.data(i) * 256 + oPropData.data(i + 1)) 240 | If oWordEntry Is Nothing Then Return False 241 | If (oWordEntry.Flags And &H20) = 0 Then Return False 242 | Next 243 | Next 244 | Return True 245 | End If 246 | End Function 247 | 248 | Private Function IdentifyZILAction(pPropEntry As PropertyEntry) As Boolean 249 | ' Length = 2, Check if all are valid routines 250 | ' 0 is valid routine IF there are other routines referenced by this property 251 | Dim bFound As Boolean = False 252 | For Each oPropData As PropertyData In pPropEntry.data 253 | If Not oPropData.data.Count = 2 Then Return False 254 | Dim iAddrRoutine As Integer = oPropData.data(0) * 256 + oPropData.data(1) 255 | If iAddrRoutine = 0 And Not bFound Then Return False 256 | If iAddrRoutine > 0 And routineList.Find(Function(x) x.entryPointPacked = iAddrRoutine) Is Nothing Then Return False 257 | bFound = True 258 | Next 259 | Return True 260 | End Function 261 | 262 | Private Function IdentifyZILHighString(pPropEntry As PropertyEntry) As Boolean 263 | ' Length = 2, Check if all are valid high strings 264 | ' 0 is valid string IF there are other strings referenced by this property 265 | Dim bFound As Boolean = False 266 | For Each oPropData As PropertyData In pPropEntry.data 267 | If Not oPropData.data.Count = 2 Then Return False 268 | Dim iAddrString As Integer = oPropData.data(0) * 256 + oPropData.data(1) 269 | If iAddrString = 0 And Not bFound Then Return False 270 | If iAddrString > 0 And stringList.Find(Function(x) x.entryPointPacked = iAddrString) Is Nothing Then Return False 271 | bFound = True 272 | Next 273 | Return True 274 | End Function 275 | 276 | Private Function IdentifyZILPseudo(pPropEntry As PropertyEntry) As Boolean 277 | ' Length mod 4 = 0, Check if all follows pattern WORD ROUTINE 278 | For Each oPropData As PropertyData In pPropEntry.data 279 | If Not (oPropData.data.Count Mod 4) = 0 Then Return False 280 | For i As Integer = 0 To oPropData.data.Count - 4 Step 4 281 | Dim iAddrWord As Integer = oPropData.data(i) * 256 + oPropData.data(i + 1) 282 | Dim iAddrRoutine As Integer = oPropData.data(i + 2) * 256 + oPropData.data(i + 3) 283 | If dictionary.GetEntryAtAddress(iAddrWord) Is Nothing Then Return False 284 | If routineList.Find(Function(x) x.entryPointPacked = iAddrRoutine) Is Nothing Then Return False 285 | Next 286 | Next 287 | Return True 288 | End Function 289 | 290 | Private Function IdentifyZILGlobal(pPropEntry As PropertyEntry) As Boolean 291 | ' Version 1-3: List of object numbers (one byte). Object 0 doesn't exists 292 | ' Version 4- : List of object numbers (two bytes). Object 0 doesn't exists 293 | ' The property should also be of different length between objects 294 | Dim bSameSize As Boolean = True 295 | For Each oPropData As PropertyData In pPropEntry.data 296 | If oPropData.data.Count <> pPropEntry.data.First.data.Count Then 297 | bSameSize = False 298 | Exit For 299 | End If 300 | Next 301 | If bSameSize Then Return False 302 | If ZVersion < 4 Then 303 | For Each oPropData As PropertyData In pPropEntry.data 304 | For i As Integer = 0 To oPropData.data.Count - 1 305 | If oPropData.data(i) = 0 Then Return False 306 | If oPropData.data(i) > objectCount Then Return False 307 | Next 308 | Next 309 | Return True 310 | Else 311 | For Each oPropData As PropertyData In pPropEntry.data 312 | If Not (oPropData.data.Count Mod 2) = 0 Then Return False 313 | For i As Integer = 0 To oPropData.data.Count - 2 Step 2 314 | Dim objectNumber As Integer = oPropData.data(i) * 256 + oPropData.data(i + 1) 315 | If objectNumber = 0 Then Return False 316 | If objectNumber > objectCount Then Return False 317 | Next 318 | Next 319 | Return True 320 | End If 321 | End Function 322 | 323 | Private Shared Function IdentifyZILValue(pPropEntry As PropertyEntry) As Boolean 324 | ' Property length always = 2 and value inside -255-255 are identified as a value 325 | For Each oPropData As PropertyData In pPropEntry.data 326 | If Not oPropData.data.Count = 2 Then Return False 327 | If oPropData.data(0) > 0 And oPropData.data(0) < 255 Then Return False 328 | Next 329 | Return True 330 | End Function 331 | 332 | Private Function IdentifyZILTable(pPropEntry As PropertyEntry) As Boolean 333 | ' Property length always = 2 and value point to area in unidentified data 334 | For Each oPropData As PropertyData In pPropEntry.data 335 | If Not oPropData.data.Count = 2 Then Return False 336 | Dim iAddress As Integer = oPropData.data(0) * 256 + oPropData.data(1) 337 | If MemoryMap.Find(Function(x) x.addressStart <= iAddress And x.addressEnd >= iAddress And x.type = MemoryMapType.MM_UNIDENTIFIED_DATA) Is Nothing Then Return False 338 | Next 339 | Return True 340 | End Function 341 | 342 | Public Function GetPropertyType(pNumber As Integer) As PropertyType 343 | Dim propEntry As PropertyEntry = properties.Find(Function(x) x.number = pNumber) 344 | If propEntry Is Nothing Then Return PropertyType.UNUSED 345 | Return propEntry.PropertyType 346 | End Function 347 | 348 | Public Function GetPropertyAmbiguityTypes(pNumber As Integer) As List(Of PropertyType) 349 | Dim propEntry As PropertyEntry = properties.Find(Function(x) x.number = pNumber) 350 | If propEntry Is Nothing Then Return New List(Of PropertyType) 351 | Return propEntry.AmbiguityTypes 352 | End Function 353 | 354 | Public Shared Function GetPropertyTypeName(pPropertyType As PropertyType) As String 355 | Select Case pPropertyType 356 | Case PropertyType.UNINITIATED : Return "Not analysed" 357 | Case PropertyType.ZIL_ACTION : Return "ACTION" 358 | Case PropertyType.ZIL_ADJECTIVE : Return "ADJECTIVE" 359 | Case PropertyType.ZIL_DIRECTION : Return "DIRECTION" 360 | Case PropertyType.ZIL_GLOBAL : Return "GLOBAL" 361 | Case PropertyType.ZIL_PSEUDO : Return "PSEUDO" 362 | Case PropertyType.SYNONYM : Return "SYNONYM" 363 | Case PropertyType.ZIL_HIGH_STRING : Return "HIGH STRING" 364 | Case PropertyType.ZIL_STRING : Return "STRING" 365 | Case PropertyType.ZIL_THINGS : Return "THINGS" 366 | Case PropertyType.ZIL_UNKNOWN : Return "UNKNOWN" 367 | Case PropertyType.ZIL_VALUE : Return "VALUE" 368 | Case PropertyType.ZIL_TABLE : Return "TABLE" 369 | Case PropertyType.AMBIGUITY : Return "AMBIGUITY" 370 | Case Else : Return "UNIDENTIFIED" 371 | End Select 372 | End Function 373 | 374 | Public ReadOnly Property Count As Integer 375 | Get 376 | Return properties.Count 377 | End Get 378 | End Property 379 | 380 | 'Private ZilPropDirectionList As New List(Of Integer) 381 | 382 | 'Private Sub DecodePropertyData(pStoryData() As Byte, pDictEntries As DictionaryEntries, pStringsList As List(Of StringData), pRoutineList As List(Of RoutineData), pPropNum As Integer, pPropSize As Integer, pPropStart As Integer, pPropData As String) 383 | ' Else 384 | ' If pDictEntries.GetDirection(pPropNum).Count > 0 Then 385 | ' ZilPropDirectionList.Add(pPropNum) 386 | ' DecodePropertyData(pStoryData, pDictEntries, pStringsList, pRoutineList, pPropNum, pPropSize, pPropStart, pPropData) 387 | ' Exit Sub 388 | ' End If 389 | ' ' Length = 2, Check is Routine, String or Word (in that order) 390 | ' ' Length mod 2 = 0, Check if all ar words 391 | ' If pPropSize = 2 Then 392 | ' Dim oStringData As StringData = pStringsList.Find(Function(c) c.entryPointPacked = Helper.GetAdressFromWord(pStoryData, pPropStart)) 393 | ' Dim oRoutineData As RoutineData = pRoutineList.Find(Function(c) c.entryPointPacked = Helper.GetAdressFromWord(pStoryData, pPropStart)) 394 | ' If oStringData IsNot Nothing Then 395 | ' Console.WriteLine("(PROP-{0} {1}{2}{3})", pPropNum, Convert.ToChar(34), oStringData.text, Convert.ToChar(34)) 396 | ' Exit Sub 397 | ' End If 398 | ' If oRoutineData IsNot Nothing Then 399 | ' Console.WriteLine("(PROP-{0} R{1:X5})", pPropNum, oRoutineData.entryPoint) 400 | ' Exit Sub 401 | ' End If 402 | ' End If 403 | ' ' Length mod 2 = 0, Check if all ar words 404 | ' If (pPropSize Mod 2) = 0 Then 405 | ' Dim bValidWords As Boolean = True 406 | ' For i As Integer = 0 To pPropSize - 2 Step 2 407 | ' If pDictEntries.GetEntryAtAddress(Helper.GetAdressFromWord(byteStory, pPropStart + i)) Is Nothing Then 408 | ' bValidWords = False 409 | ' Exit For 410 | ' End If 411 | ' Next 412 | ' If bValidWords Then 413 | ' Console.Write("(PROP-{0}", pPropNum) 414 | ' For i As Integer = 0 To pPropSize - 2 Step 2 415 | ' Console.Write(" {0}", pDictEntries.GetEntryAtAddress(Helper.GetAdressFromWord(byteStory, pPropStart + i)).dictWord.ToUpper) 416 | ' Next 417 | ' Console.WriteLine(")") 418 | ' Exit Sub 419 | ' End If 420 | ' End If 421 | ' ' Length mod 2 = 0, Check if they are a pattern WORD FUNCTION, then PSEUDO 422 | ' If (pPropSize Mod 2) = 0 And pPropSize > 3 Then 423 | ' Dim bValidPseudo As Boolean = True 424 | ' For i As Integer = 0 To pPropSize - 4 Step 4 425 | ' Dim iIdx As Integer = pPropStart + i + 2 426 | ' If pDictEntries.GetEntryAtAddress(Helper.GetAdressFromWord(byteStory, pPropStart + i)) Is Nothing Or 427 | ' pRoutineList.Find(Function(c) c.entryPointPacked = Helper.GetAdressFromWord(byteStory, iIdx)) Is Nothing Then 428 | ' bValidPseudo = False 429 | ' Exit For 430 | ' End If 431 | ' Next 432 | ' If bValidPseudo Then 433 | ' Console.Write("(PSEUDO") 434 | ' For i As Integer = 0 To pPropSize - 4 Step 4 435 | ' Dim iIdx As Integer = pPropStart + i + 2 436 | ' Dim oRoutineData As RoutineData = pRoutineList.Find(Function(c) c.entryPointPacked = Helper.GetAdressFromWord(byteStory, iIdx)) 437 | ' Console.Write(" {0}{1}{2}", Convert.ToChar(34), pDictEntries.GetEntryAtAddress(Helper.GetAdressFromWord(byteStory, pPropStart + i)).dictWord.ToUpper, Convert.ToChar(34)) 438 | ' Console.Write(" R{0:X5}", oRoutineData.entryPoint) 439 | ' Next 440 | ' Console.WriteLine(")") 441 | ' Exit Sub 442 | ' End If 443 | ' End If 444 | ' Console.WriteLine("Data = {0}", pPropData) 445 | ' End If 446 | ' ElseIf {eCompiler.INFORM5, eCompiler.INFORM6}.Contains(compilerSource) Then 447 | ' ' Length = 2, Check is Routine, String or Word (in that order) 448 | ' ' Length mod 2 = 0, Check if all ar words 449 | ' If pPropSize = 2 Then 450 | ' Dim oStringData As StringData = pStringsList.Find(Function(c) c.entryPointPacked = Helper.GetAdressFromWord(pStoryData, pPropStart)) 451 | ' Dim oRoutineData As RoutineData = pRoutineList.Find(Function(c) c.entryPointPacked = Helper.GetAdressFromWord(pStoryData, pPropStart)) 452 | ' If oStringData IsNot Nothing Then 453 | ' Console.WriteLine("prop-{0} {1}{2}{3}", pPropNum, Convert.ToChar(34), oStringData.text, Convert.ToChar(34)) 454 | ' Exit Sub 455 | ' End If 456 | ' If oRoutineData IsNot Nothing Then 457 | ' Console.WriteLine("prop-{0} R{1:X5}", pPropNum, oRoutineData.entryPoint) 458 | ' Exit Sub 459 | ' End If 460 | ' End If 461 | ' If (pPropSize Mod 2) = 0 Then 462 | ' Dim bValidWords As Boolean = True 463 | ' For i As Integer = 0 To pPropSize - 2 Step 2 464 | ' If pDictEntries.GetEntryAtAddress(Helper.GetAdressFromWord(byteStory, pPropStart + i)) Is Nothing Then 465 | ' bValidWords = False 466 | ' Exit For 467 | ' End If 468 | ' Next 469 | ' If bValidWords Then 470 | ' Console.Write("prop-{0}", pPropNum) 471 | ' For i As Integer = 0 To pPropSize - 2 Step 2 472 | ' Console.Write(" '{0}'", pDictEntries.GetEntryAtAddress(Helper.GetAdressFromWord(byteStory, pPropStart + i)).dictWord) 473 | ' Next 474 | ' Console.WriteLine() 475 | ' Exit Sub 476 | ' End If 477 | ' Console.WriteLine("Data = {0}", pPropData) 478 | ' End If 479 | ' Else 480 | ' Console.WriteLine("Data = {0}", pPropData) 481 | ' End If 482 | 'End Sub 483 | 484 | End Class 485 | -------------------------------------------------------------------------------- /UnZ/Decode.vb: -------------------------------------------------------------------------------- 1 | 'MIT License 2 | 3 | 'Copyright(c) 2021-2025 Henrik Åsman 4 | 5 | 'Permission Is hereby granted, free Of charge, to any person obtaining a copy 6 | 'of this software And associated documentation files (the "Software"), to deal 7 | 'in the Software without restriction, including without limitation the rights 8 | 'to use, copy, modify, merge, publish, distribute, sublicense, And/Or sell 9 | 'copies of the Software, And to permit persons to whom the Software Is 10 | 'furnished to do so, subject to the following conditions: 11 | 12 | 'The above copyright notice And this permission notice shall be included In all 13 | 'copies Or substantial portions of the Software. 14 | 15 | 'THE SOFTWARE Is PROVIDED "AS IS", WITHOUT WARRANTY Of ANY KIND, EXPRESS Or 16 | 'IMPLIED, INCLUDING BUT Not LIMITED To THE WARRANTIES Of MERCHANTABILITY, 17 | 'FITNESS FOR A PARTICULAR PURPOSE And NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | 'AUTHORS Or COPYRIGHT HOLDERS BE LIABLE For ANY CLAIM, DAMAGES Or OTHER 19 | 'LIABILITY, WHETHER In AN ACTION Of CONTRACT, TORT Or OTHERWISE, ARISING FROM, 20 | 'OUT OF Or IN CONNECTION WITH THE SOFTWARE Or THE USE Or OTHER DEALINGS IN THE 21 | 'SOFTWARE. 22 | 23 | Imports System.Drawing 24 | Imports System.Net 25 | Imports System.Net.Mime.MediaTypeNames 26 | Imports System.Runtime.InteropServices 27 | Imports System.Runtime.Intrinsics.Arm 28 | 29 | Public Class Decode 30 | Public startAddress As Integer = 0 31 | Public endAddress As Integer = 0 32 | Public localsCount As Integer = 0 33 | Public highest_routine As Integer = 0 34 | Public lowest_routine As Integer = Integer.MaxValue 35 | Public lowest_string As Integer = Integer.MaxValue 36 | Public highest_global As Integer = -1 37 | Public callsTo As New List(Of CallsFromTo) 38 | Private ZVersion As Integer = 0 39 | Private PC As Integer = 0 40 | Private byteGame() As Byte 41 | Private high_pc As Integer 42 | Private sAbbreviations() As String 43 | Private bSilent As Boolean = False 44 | Private bShowZCodeVerbose As Boolean = False 45 | Private syntax As Integer = 0 46 | Private validStringList As List(Of StringData) = Nothing 47 | Private validRoutineList As List(Of RoutineData) = Nothing 48 | Private DictEntriesList As New DictionaryEntries 49 | Private alphabet(2) As String 50 | Private propertyMax As Integer = 63 51 | Private propertyMin As Integer = 0 52 | Private showAbbrevsInsertion As Boolean = True 53 | Private inlineStrings As List(Of InlineString) 54 | Public arraysStart As New HashSet(Of Integer) 55 | Public usedGlobals As New HashSet(Of Integer) 56 | 57 | Public Enum EnumOpcodeClass 58 | EXTENDED_OPERAND 59 | TWO_OPERAND 60 | ONE_OPERAND 61 | ZERO_OPERAND 62 | VARIABLE_OPERAND 63 | End Enum 64 | 65 | Public Enum EnumOperand 66 | P_NIL 67 | P_ANYTHING 68 | P_VAR 69 | P_NUMBER 70 | P_LOW_ADDR 71 | P_ROUTINE 72 | P_OBJECT 73 | P_STATIC 74 | P_LABEL 75 | P_PCHAR 76 | P_VATTR 77 | P_PATTR 78 | P_INDIRECT 79 | P_PROPNUM 80 | P_ATTRNUM 81 | End Enum 82 | 83 | Public Enum EnumExtra 84 | E_NONE 85 | E_TEXT 86 | E_STORE 87 | E_BRANCH 88 | E_BOTH 89 | End Enum 90 | 91 | Public Enum EnumType 92 | T_PLAIN 93 | T_CALL 94 | T_RETURN 95 | T_ILLEGAL 96 | End Enum 97 | 98 | Public Enum EnumStatus 99 | END_OF_CODE 100 | END_OF_ROUTINE 101 | END_OF_INSTRUCTION 102 | BAD_ENTRY 103 | BAD_OPCODE 104 | End Enum 105 | 106 | Public Enum EnumAddressMode 107 | NONE 108 | LONG_IMMEDIATE 109 | IMMEDIATE 110 | VARIABLE 111 | End Enum 112 | 113 | Private Class DecodeResult 114 | Public status As EnumStatus 115 | Public nextPC As Integer 116 | End Class 117 | 118 | Private Class Opcode 119 | Public Address As Integer 120 | Public Code As Integer 121 | Public ExtModeByte As Integer 122 | Public OpcodeClass As EnumOpcodeClass 123 | Public OperandType(7) As EnumOperand 124 | Public OperandLen(7) As Integer 125 | Public OperandVal(7) As Integer 126 | Public OperandAddrMode(7) As EnumAddressMode 127 | Public OperandStringPseudo(7) As String 128 | Public Extra As EnumExtra 129 | Public StoreVal As Integer = 0 130 | Public StoreStringPseudo As String 131 | Public BranchTest As Boolean = True ' Branch if true/false 132 | Public BranchAddr As Integer = 0 ' Absolut address of branch, 0=false, 1=true 133 | Public Type As EnumType 134 | Public Text As String = "" 135 | Public OperandText As String = "" 136 | Public OpcodeText As String = "" 137 | Public OpcodeBytes(20) As Byte 138 | 139 | Public Sub PrintVerbose() 140 | Dim currentByte As Integer = 0 141 | Dim byteValue As Integer 142 | Dim wordValue As Integer 143 | Dim numberOfOperands As Integer = 0 144 | 145 | Console.WriteLine(" *--------------------------------------------------") 146 | 147 | ' Opcode 148 | Dim opcodeAsBinary As String = Convert.ToString(Code Or 256, 2).Substring(1) 149 | Console.WriteLine(" |Opcode:") 150 | Select Case OpcodeClass 151 | Case EnumOpcodeClass.ZERO_OPERAND ' Bit 7-4 = 1011 152 | Console.WriteLine(" | Byte {0,2:##} 0OP:{1}", currentByte + 1, Code) 153 | Console.WriteLine(" | {0} 0x{1:X2} {2}", opcodeAsBinary, Code, Code) 154 | Console.WriteLine(" | 10 short-form (long-form in ZAP)") 155 | Console.WriteLine(" | 11 no operands") 156 | Console.WriteLine(" | {0} {1}", opcodeAsBinary.Substring(4, 4), OpcodeText) 157 | Case EnumOpcodeClass.ONE_OPERAND ' Bit 7-6 = 10 158 | numberOfOperands = 1 159 | Console.WriteLine(" | Byte {0,2:##} 1OP:{1}", currentByte + 1, Code And &H9F) 160 | Console.WriteLine(" | {0} 0x{1:X2} {2}", opcodeAsBinary, Code, Code) 161 | Console.WriteLine(" | 10 short-form (long-form in ZAP)") 162 | Console.WriteLine(" | {0} {1}", opcodeAsBinary.Substring(2, 2), OperandDescription((Code >> 4) And &H3)) 163 | 'End Select 164 | Console.WriteLine(" | {0} {1}", opcodeAsBinary.Substring(4, 4), OpcodeText) 165 | Case EnumOpcodeClass.TWO_OPERAND ' Bit 7 = 0 166 | numberOfOperands = 2 167 | Console.WriteLine(" | Byte {0,2:##} 2OP:{1}", currentByte + 1, Code And &H1F) 168 | Console.WriteLine(" | {0} 0x{1:X2} {2}", opcodeAsBinary, Code, Code) 169 | Console.WriteLine(" | 0 long-form (short-form in ZAP)") 170 | Select Case Code And &H60 171 | Case &H0 172 | Console.WriteLine(" | 0 constant (immediate)") 173 | Console.WriteLine(" | 0 constant (immediate)") 174 | Case &H20 175 | Console.WriteLine(" | 0 constant (immediate)") 176 | Console.WriteLine(" | 1 variable") 177 | Case &H40 178 | Console.WriteLine(" | 1 variable") 179 | Console.WriteLine(" | 0 constant (immediate)") 180 | Case &H60 181 | Console.WriteLine(" | 1 variable") 182 | Console.WriteLine(" | 1 variable") 183 | End Select 184 | Console.WriteLine(" | {0} {1}", opcodeAsBinary.Substring(3, 5), OpcodeText) 185 | Case EnumOpcodeClass.VARIABLE_OPERAND ' Bit 7-6 = 11 186 | numberOfOperands = 4 187 | Console.WriteLine(" | Byte {0,2:##} VAR:{1} (EXT:{2})", currentByte + 1, Code, Code) 188 | Console.WriteLine(" | {0} 0x{1:X2} {2}", opcodeAsBinary, Code, Code) 189 | Console.WriteLine(" | 11 variable-operand (extended)") 190 | If Code < 224 Then 191 | Console.WriteLine(" | 0 VAR-variant of 2OP:{0}", Code - 192) 192 | Else 193 | Console.WriteLine(" | 1 VAR") 194 | End If 195 | Console.WriteLine(" | {0} {1}", opcodeAsBinary.Substring(3, 5), OpcodeText) 196 | Case EnumOpcodeClass.EXTENDED_OPERAND ' 0OP opcode 190 197 | numberOfOperands = 4 198 | Console.WriteLine(" | Byte {0,2:##} 0OP:190 extended-form (EXTOP)") 199 | Console.WriteLine(" | 10111110 0xBE 190") 200 | currentByte += 1 201 | Console.WriteLine(" | Byte {0,2:##} EXT:{1} (EXT:{2})", currentByte + 1, Code, Code + 256) 202 | Console.WriteLine(" | {0} 0x{1:X2} {2}", opcodeAsBinary, Code, Code) 203 | End Select 204 | currentByte += 1 205 | 206 | ' Operand types 207 | byteValue = OpcodeBytes(currentByte) 208 | Dim operandTypesAsBinary As String = Convert.ToString(byteValue Or 256, 2).Substring(1) 209 | If OpcodeClass = EnumOpcodeClass.VARIABLE_OPERAND Or OpcodeClass = EnumOpcodeClass.EXTENDED_OPERAND Then 210 | If byteValue = &HFF Then numberOfOperands = 0 211 | Console.WriteLine(" |") 212 | Console.WriteLine(" |Operand types:") 213 | Console.WriteLine(" | Byte {0,2:##} Operand types 1-4", currentByte + 1) 214 | Console.WriteLine(" | {0} 0x{1:X2} {2}", operandTypesAsBinary, byteValue, byteValue) 215 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(0, 2), OperandDescription((byteValue >> 6) And &H3)) 216 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(2, 2), OperandDescription((byteValue >> 4) And &H3)) 217 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(4, 2), OperandDescription((byteValue >> 2) And &H3)) 218 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(6, 2), OperandDescription(byteValue And &H3)) 219 | currentByte += 1 220 | If (Code And &H3F) = &H2C Or (Code And &H3F) = &H3A Then 221 | ' These two opcodes are special and have an extra byte for operand types 222 | If byteValue = &HFF Then numberOfOperands = 0 Else numberOfOperands = 8 223 | byteValue = OpcodeBytes(currentByte) 224 | operandTypesAsBinary = Convert.ToString(byteValue Or 256, 2).Substring(1) 225 | Console.WriteLine(" | Byte {0,2:##} Operand types 5-8", currentByte + 1) 226 | Console.WriteLine(" | {0} 0x{1:X2} {2}", operandTypesAsBinary, byteValue, byteValue) 227 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(0, 2), OperandDescription((byteValue >> 6) And &H3)) 228 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(2, 2), OperandDescription((byteValue >> 4) And &H3)) 229 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(4, 2), OperandDescription((byteValue >> 2) And &H3)) 230 | Console.WriteLine(" | {0} {1}", operandTypesAsBinary.Substring(6, 2), OperandDescription(byteValue And &H3)) 231 | currentByte += 1 232 | End If 233 | End If 234 | 235 | ' Operands 236 | If numberOfOperands > 0 Then 237 | Console.WriteLine(" |") 238 | Console.WriteLine(" |Operands:") 239 | For i As Integer = 0 To numberOfOperands - 1 240 | byteValue = OpcodeBytes(currentByte) 241 | Select Case OperandAddrMode(i) 242 | Case EnumAddressMode.IMMEDIATE 243 | If OperandType(i) = EnumOperand.P_VAR Then 244 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2} ({3})", currentByte + 1, byteValue, byteValue, VariableDescription(byteValue)) 245 | ElseIf (byteValue And &H8000) > 0 Then 246 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2} / {3}", currentByte + 1, byteValue, byteValue, -1 * (&H100 - byteValue)) 247 | Else 248 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2}", currentByte + 1, byteValue, byteValue) 249 | End If 250 | currentByte += 1 251 | Case EnumAddressMode.VARIABLE 252 | Dim varText As String = VariableDescription(byteValue) 253 | If OperandType(i) = EnumOperand.P_INDIRECT Then varText = "[" & varText & "]" 254 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2} ({3})", currentByte + 1, byteValue, byteValue, varText) 255 | currentByte += 1 256 | Case EnumAddressMode.LONG_IMMEDIATE 257 | wordValue = OpcodeBytes(currentByte) * 256 + OpcodeBytes(currentByte + 1) 258 | If OperandType(i) = EnumOperand.P_LABEL Then 259 | ' JUMP, always two-complemented word 260 | If (wordValue And &H8000) > 0 Then 261 | Console.WriteLine(" | Byte {0,2:##}-{1,2:##} 0x{2:X4} {3} [{4} (0x{5:X4}) - {6} - 2 = {7} (0x{8:X4})]", currentByte + 1, 262 | currentByte + 2, 263 | wordValue, 264 | -1 * (&H10000 - wordValue), 265 | Address + currentByte + 2, 266 | Address + currentByte + 2, 267 | &H10000 - wordValue, 268 | Address + currentByte + 2 - (&H10000 - wordValue) - 2, 269 | Address + currentByte + 2 - (&H10000 - wordValue) - 2) 270 | Else 271 | Console.WriteLine(" | Byte {0,2:##}-{1,2:##} 0x{2:X4} {3} [{4} (0x{5:X4}) + {6} - 2 = {7} (0x{8:X4})]", currentByte + 1, 272 | currentByte + 2, 273 | wordValue, 274 | wordValue, 275 | Address + currentByte + 2, 276 | Address + currentByte + 2, 277 | wordValue, 278 | Address + currentByte + 2 + wordValue - 2, 279 | Address + currentByte + 2 + wordValue - 2) 280 | End If 281 | Else 282 | If (wordValue And &H8000) > 0 Then 283 | Console.WriteLine(" | Byte {0,2:##}-{1,2:##} 0x{2:X4} {3} / {4}", currentByte + 1, currentByte + 2, wordValue, wordValue, -1 * (&H10000 - wordValue)) 284 | Else 285 | Console.WriteLine(" | Byte {0,2:##}-{1,2:##} 0x{2:X4} {3}", currentByte + 1, currentByte + 2, wordValue, wordValue) 286 | End If 287 | End If 288 | currentByte += 2 289 | End Select 290 | 291 | Next 292 | End If 293 | 294 | ' Store 295 | If Extra = EnumExtra.E_STORE Or Extra = EnumExtra.E_BOTH Then 296 | byteValue = OpcodeBytes(currentByte) 297 | Console.WriteLine(" |") 298 | Console.WriteLine(" |Store:") 299 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2} ({3})", currentByte + 1, byteValue, byteValue, VariableDescription(byteValue)) 300 | currentByte += 1 301 | End If 302 | 303 | ' Branch 304 | If Extra = EnumExtra.E_BRANCH Or Extra = EnumExtra.E_BOTH Then 305 | Console.WriteLine(" |") 306 | Console.WriteLine(" |Branch:") 307 | byteValue = OpcodeBytes(currentByte) 308 | wordValue = OpcodeBytes(currentByte) * 256 + OpcodeBytes(currentByte + 1) 309 | Dim predicateAsBinary As String = Convert.ToString(byteValue Or 256, 2).Substring(1) 310 | If (byteValue And &H40) = &H40 Then 311 | ' 6-bit branch, always forward 312 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2}", currentByte + 1, byteValue, byteValue) 313 | Console.WriteLine(" | {0} ", operandTypesAsBinary) 314 | If (byteValue And &H80) = &H80 Then 315 | Console.WriteLine(" | 1 branch if true") 316 | Else 317 | Console.WriteLine(" | 0 branch if false") 318 | End If 319 | Console.WriteLine(" | 1 6-bit branch, always forward, except when 0 (rfalse) or 1 (rtrue)") 320 | If (byteValue And &H3F) = 0 Then 321 | Console.WriteLine(" | {0} 0x{1:X2} {2} (rfalse)", predicateAsBinary.Substring(2, 6), byteValue And &H3F, byteValue And &H3F) 322 | ElseIf (byteValue And &H3F) = 1 Then 323 | Console.WriteLine(" | {0} 0x{1:X2} {2} (rtrue)", predicateAsBinary.Substring(2, 6), byteValue And &H3F, byteValue And &H3F) 324 | Else 325 | Console.WriteLine(" | {0} 0x{1:X2} {2} [{3} (0x{4:X4}) + {5} - 2 = {6} (0x{7:X4})]", predicateAsBinary.Substring(2, 6), 326 | byteValue And &H3F, 327 | byteValue And &H3F, 328 | Address + currentByte + 1, 329 | Address + currentByte + 1, 330 | byteValue And &H3F, 331 | Address + currentByte + 1 + (byteValue And &H3F) - 2, 332 | Address + currentByte + 1 + (byteValue And &H3F) - 2) 333 | End If 334 | currentByte += 1 335 | Else 336 | ' 14-bit branch, two-complemented 337 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2}", currentByte + 1, byteValue, byteValue) 338 | Console.WriteLine(" | {0} ", operandTypesAsBinary) 339 | If (byteValue And &H80) = &H80 Then 340 | Console.WriteLine(" | 1 branch if true") 341 | Else 342 | Console.WriteLine(" | 0 branch if false") 343 | End If 344 | Console.WriteLine(" | 0 14-bit branch, two-complemented") 345 | Console.WriteLine(" | {0} high 6 bits", predicateAsBinary.Substring(2, 6)) 346 | currentByte += 1 347 | byteValue = OpcodeBytes(currentByte) 348 | predicateAsBinary = Convert.ToString(byteValue Or 256, 2).Substring(1) 349 | Console.WriteLine(" | Byte {0,2:##} 0x{1:X2} {2}, low 8 bits", currentByte + 1, byteValue, byteValue) 350 | If (wordValue And &H2000) = &H2000 Then 351 | Dim value As Integer = &H4000 - (wordValue And &H3FFF) 352 | Console.WriteLine(" | {0} 0x{1:X4} {2} [{3} (0x{4:X4}) - {5} - 2 = {6} (0x{7:X4})]", predicateAsBinary, 353 | -1 * value, 354 | -1 * value, 355 | Address + currentByte + 1, 356 | Address + currentByte + 1, 357 | value, 358 | Address + currentByte + 1 - value - 2, 359 | Address + currentByte + 1 - value - 2) 360 | 361 | Else 362 | Console.WriteLine(" | {0} 0x{1:X4} {2} [{3} (0x{4:X4}) + {5} - 2 = {6} (0x{7:X4})]", predicateAsBinary, 363 | wordValue And &H3FFF, 364 | wordValue And &H3FFF, 365 | Address + currentByte + 1, 366 | Address + currentByte + 1, 367 | wordValue And &H3FFF, 368 | Address + currentByte + 1 + (wordValue And &H3FFF) - 2, 369 | Address + currentByte + 1 + (wordValue And &H3FFF) - 2) 370 | End If 371 | currentByte += 1 372 | End If 373 | End If 374 | 375 | ' Text 376 | If Extra = EnumExtra.E_TEXT Then 377 | Console.WriteLine(" |") 378 | Console.WriteLine(" |Text:") 379 | Console.WriteLine(" | Byte {0,2:##}- string encoded in ZSCII", currentByte + 1) 380 | End If 381 | 382 | ' Pseudo 383 | Dim pseudoCodeString As String = PseudoCode() 384 | Console.WriteLine(" |") 385 | Console.WriteLine(" |Pseudo-code:") 386 | Console.WriteLine(" | {0}", pseudoCodeString) 387 | 388 | Console.WriteLine(" *--------------------------------------------------") 389 | End Sub 390 | 391 | Public Function PseudoCode() As String 392 | Dim pseudoCodeString As String = "not implemented" 393 | Dim stackPeek As Boolean = False 394 | If Extra = EnumExtra.E_BRANCH Or Extra = EnumExtra.E_BOTH Then 395 | 'check_arg_count, ASSIGNED? if (check_arg_count > arg1) jump xxxx/rfalse/rtrue 396 | 'dec_chk, DLESS? var = var - 1; if (var = int) jump xxxx/rfalse/rtrue 397 | 'get_child, FIRST? VAL = child(obj); if (VAL ==/~= nothing) jump xxxx/rfalse/rtrue 398 | 'get_sibling, NEXT? VAL = sibling(obj); if (VAL ==/~= nothing) jump xxxx/rfalse/rtrue 399 | 'inc_chk", "IGRTR?" var = var + 1; if (var >/<= int) jump xxxx/rfalse/rtrue 400 | 'je, EQUAL? if (arg1 ==/~= arg2 [or arg3]...) jump xxxx/rfalse/rtrue 401 | 'jg, GRTR? if (arg1 >/<= arg2) jump xxxx/rfalse/rtrue 402 | 'jin, IN? if (arg1 in/notin arg2) jump xxxx/rfalse/rtrue 403 | 'jl, LESS? if (arg1 = arg2) jump xxxx/rfalse/rtrue 404 | 'jz, ZERO? if (arg ==/~= 0) jump xxxx/rfalse/rtrue 405 | 'make_menu, MENU if (make_menu(arg1, arg2) == true/false) jump xxxx/rfalse/rtrue 406 | 'picture_data, PICINF if (picture_data(arg1, arg2) == true/false) jump xxxx/rfalse/rtrue 407 | 'piracy, ORIGINAL? if (orginal == true/false) jump xxxx/rfalse/rtrue 408 | 'push_stack, XPUSH if (push_stack(arg1) == true/false) jump xxxx/rfalse/rtrue 409 | 'restore, RESTORE if (restore == true/false) jump xxxx/rfalse/rtrue 410 | 'save, SAVE if (save == true/false) jump xxxx/rfalse/rtrue 411 | 'scan_table, INTBL? VAL = scan_table(arg1, arg2, arg3[, arg4]); if (VAL ==/~= nothing) jump xxxx/rfalse/rtrue 412 | 'test, BTST if ((arg1 & arg2) ==/~= arg2) jump xxxx/rfalse/rtrue 413 | 'test_attr, FSET? if (arg1 has/hasnt arg2) jump xxxx/rfalse/rtrue 414 | 'verify, VERIFY if (verify == true/false) jump xxxx/rfalse/rtrue 415 | Dim pseudoComp As String 416 | Select Case OpcodeText 417 | Case "@check_arg_count / ASSIGNED?" 418 | If BranchTest Then pseudoComp = "==" Else pseudoComp = "~=" 419 | pseudoCodeString = String.Concat("if (check_arg_count() ", pseudoComp, " ", OperandStringPseudo(0), ") ", PseudoBranchText, ";") 420 | Case "@dec_chk / DLESS?" 421 | If BranchTest Then pseudoComp = "<" Else pseudoComp = ">=" 422 | pseudoCodeString = String.Concat(OperandStringPseudo(0), " = ", OperandStringPseudo(0), " - 1; if (", OperandStringPseudo(0), " ", pseudoComp, " ", OperandStringPseudo(1), ") ", PseudoBranchText, ";") 423 | Case "@get_child / FIRST?" 424 | stackPeek = True 425 | If BranchTest Then pseudoComp = "==" Else pseudoComp = "~=" 426 | pseudoCodeString = String.Concat(StoreStringPseudo, " = child(", OperandStringPseudo(0), ")#; if (", StoreStringPseudo, " ", pseudoComp, " nothing) ", PseudoBranchText, ";") 427 | Case "@get_sibling / NEXT?" 428 | stackPeek = True 429 | If BranchTest Then pseudoComp = "==" Else pseudoComp = "~=" 430 | pseudoCodeString = String.Concat(StoreStringPseudo, " = sibling(", OperandStringPseudo(0), ")#; if (", StoreStringPseudo, " ", pseudoComp, " nothing) ", PseudoBranchText, ";") 431 | Case "@inc_chk / IGRTR?" 432 | stackPeek = True 433 | If BranchTest Then pseudoComp = "<" Else pseudoComp = ">=" 434 | pseudoCodeString = String.Concat(OperandStringPseudo(0), " = ", OperandStringPseudo(0), " + 1; if (", OperandStringPseudo(0), " ", pseudoComp, " ", OperandStringPseudo(1), ") ", PseudoBranchText, ";") 435 | Case "@je / EQUAL?" 436 | If BranchTest Then pseudoComp = "==" Else pseudoComp = "~=" 437 | pseudoCodeString = String.Concat("if (", OperandStringPseudo(0), " ", pseudoComp, " ", PseudoConcatOperands(1, 3, " or "), ") ", PseudoBranchText, ";") 438 | Case "@jg / GRTR?" 439 | If BranchTest Then pseudoComp = ">" Else pseudoComp = "<=" 440 | pseudoCodeString = String.Concat("if (", OperandStringPseudo(0), " ", pseudoComp, " ", OperandStringPseudo(1), ") ", PseudoBranchText, ";") 441 | Case "@jin / IN?" 442 | If BranchTest Then pseudoComp = "in" Else pseudoComp = "notin" 443 | pseudoCodeString = String.Concat("if (", OperandStringPseudo(0), " ", pseudoComp, " ", OperandStringPseudo(1), ") ", PseudoBranchText, ";") 444 | Case "@jl / LESS?" 445 | If BranchTest Then pseudoComp = "<" Else pseudoComp = ">=" 446 | pseudoCodeString = String.Concat("if (", OperandStringPseudo(0), " ", pseudoComp, " ", OperandStringPseudo(1), ") ", PseudoBranchText, ";") 447 | Case "@jz / ZERO?" 448 | If BranchTest Then pseudoComp = "==" Else pseudoComp = "~=" 449 | pseudoCodeString = String.Concat("if (", OperandStringPseudo(0), " ", pseudoComp, " 0) ", PseudoBranchText, ";") 450 | Case "@make_menu / MENU" 451 | If BranchTest Then pseudoComp = "true" Else pseudoComp = "false" 452 | pseudoCodeString = String.Concat("if (make_menu(", OperandStringPseudo(0), ", ", OperandStringPseudo(1), ") ", pseudoComp, ") ", PseudoBranchText, ";") 453 | Case "@picture_data / PICINF" 454 | If BranchTest Then pseudoComp = "true" Else pseudoComp = "false" 455 | pseudoCodeString = String.Concat("if (picture_data(", OperandStringPseudo(0), ", ", OperandStringPseudo(1), ") ", pseudoComp, ") ", PseudoBranchText, ";") 456 | Case "@piracy / ORIGINAL?" 457 | If BranchTest Then pseudoComp = "true" Else pseudoComp = "false" 458 | pseudoCodeString = String.Concat("if (original() == ", pseudoComp, ") ", PseudoBranchText, ";") 459 | Case "@push_stack / XPUSH" 460 | If BranchTest Then pseudoComp = "true" Else pseudoComp = "false" 461 | pseudoCodeString = String.Concat("if (push_stack(", OperandStringPseudo(0), ") == ", pseudoComp, ") ", PseudoBranchText, ";") 462 | Case "@restore / RESTORE" 463 | If BranchTest Then pseudoComp = "true" Else pseudoComp = "false" 464 | pseudoCodeString = String.Concat("if (restore() == ", pseudoComp, ") ", PseudoBranchText, ";") 465 | Case "@save / SAVE" 466 | If BranchTest Then pseudoComp = "true" Else pseudoComp = "false" 467 | pseudoCodeString = String.Concat("if (save() == ", pseudoComp, ") ", PseudoBranchText, ";") 468 | Case "@scan_table / INTBL?" 469 | stackPeek = True 470 | If BranchTest Then pseudoComp = "==" Else pseudoComp = "~=" 471 | pseudoCodeString = String.Concat(StoreStringPseudo, " = scan_table(", PseudoConcatOperands(1), ")#; if (", StoreStringPseudo, " ", pseudoComp, " nothing) ", PseudoBranchText, ";") 472 | Case "@test / BTST" 473 | If BranchTest Then pseudoComp = "==" Else pseudoComp = "~=" 474 | pseudoCodeString = String.Concat("if ((", OperandStringPseudo(0), " & ", OperandStringPseudo(1), ") ", pseudoComp, " ", OperandStringPseudo(1), ") ", PseudoBranchText, ";") 475 | Case "@test_attr / FSET?" 476 | If BranchTest Then pseudoComp = "has" Else pseudoComp = "hasnt" 477 | pseudoCodeString = String.Concat("if (", OperandStringPseudo(0), " ", pseudoComp, " ", OperandStringPseudo(1), ") ", PseudoBranchText, ";") 478 | Case "@verify / VERIFY" 479 | If BranchTest Then pseudoComp = "true" Else pseudoComp = "false" 480 | pseudoCodeString = String.Concat("if (verify() == ", pseudoComp, ") ", PseudoBranchText, ";") 481 | End Select 482 | ElseIf Extra = EnumExtra.E_STORE Then 483 | 'add, ADD 484 | 'And, BAND 485 | 'art_shift, ASHIFT 486 | 'buffer_screen, *BUFFER_SCREEN* 487 | 'Call, CALL 488 | 'call_1s, CALL1 489 | 'call_2s, CALL2 490 | 'call_vs, CALL 491 | 'call_vs2, XCALL 492 | 'Catch, CATCH 493 | 'check_unicode, CHECKU 494 | 'div, DIV 495 | 'get_parent, LOC 496 | 'get_prop, GETP 497 | 'get_prop_addr, GETPT 498 | 'get_prop_len, PTSIZE 499 | 'get_wind_prop, WINGET 500 | 'get_next_prop, NEXTP 501 | 'load, VALUE 502 | 'loadb, GETB 503 | 'loadw, GET 504 | 'log_shift, SHIFT 505 | 'Mod, MOD 506 | 'mul, MUL 507 | 'Not, BCOM 508 | 'Or, BOR 509 | 'pull, POP 510 | 'Random, RANDOM 511 | 'read, READ 512 | 'read_char, INPUT 513 | 'restore, RESTORE 514 | 'restore_undo, IRESTORE 515 | 'save, SAVE 516 | 'save_undo, ISAVE 517 | 'set_font, FONT 518 | 'Sub, SUB 519 | Select Case OpcodeText 520 | Case "@add / ADD" 521 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " + ", OperandStringPseudo(1), "#;") 522 | Case "@and / BAND" 523 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " & ", OperandStringPseudo(1), "#;") 524 | Case "@art_shift / ASHIFT" 525 | Dim direction As String = "<<" 526 | If OperandStringPseudo(1).Substring(1, 1) = "-" Then 527 | direction = ">>" 528 | OperandStringPseudo(1) = OperandStringPseudo(1).Substring(1) 529 | End If 530 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " ", direction, " ", OperandStringPseudo(1), "#;") 531 | Case "@buffer_screen / *BUFFER_SCREEN*" 532 | pseudoCodeString = String.Concat(StoreStringPseudo, " = buffer_screen(", OperandStringPseudo(0), ")#;") 533 | Case "@call / CALL", "@call_1s / CALL1", "@call_2s / CALL2", "@call_vs / CALL", "@call_vs2 / XCALL" 534 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), "(", PseudoConcatOperands(1), ")#;") 535 | Case "@catch / CÁTCH" 536 | pseudoCodeString = String.Concat(StoreStringPseudo, " = catch();") 537 | Case "@check_unicode / CHECKU" 538 | pseudoCodeString = String.Concat(StoreStringPseudo, " = check_unicode(", OperandStringPseudo(0), ")#;") 539 | Case "@div / DIV" 540 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " / ", OperandStringPseudo(1), "#;") 541 | Case "@get_parent / LOC" 542 | pseudoCodeString = String.Concat(StoreStringPseudo, " = parent(", OperandStringPseudo(0), ")#;") 543 | Case "@get_prop / GETP" 544 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), ".", OperandStringPseudo(1), "#;") 545 | Case "@get_prop_addr / GETPT" 546 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), ".&", OperandStringPseudo(1), "#;") 547 | Case "@get_prop_len / PTSIZE" 548 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), ".#", OperandStringPseudo(1), "#;") 549 | Case "@get_wind_prop / WINGET" 550 | pseudoCodeString = String.Concat(StoreStringPseudo, " = get_wind_prop(", OperandStringPseudo(0), ", ", OperandStringPseudo(1), ")#;") 551 | Case "@get_next_prop / NEXTP" 552 | pseudoCodeString = String.Concat(StoreStringPseudo, " = get_next_prop(", OperandStringPseudo(0), ", ", OperandStringPseudo(1), ")#;") 553 | Case "@load / VALUE" 554 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), "#;") 555 | Case "@loadb / GETB" 556 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), "->", OperandStringPseudo(1), "#;") 557 | Case "@loadw / GET" 558 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), "-->", OperandStringPseudo(1), "#;") 559 | Case "@log_shift / SHIFT" 560 | Dim direction As String = "<<" 561 | If OperandStringPseudo(1).Substring(1, 1) = "-" Then 562 | direction = ">>>" 563 | OperandStringPseudo(1) = OperandStringPseudo(1).Substring(1) 564 | End If 565 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " ", direction, " ", OperandStringPseudo(1), "#;") 566 | Case "@mod / MOD" 567 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " % ", OperandStringPseudo(1), "#;") 568 | Case "@mul / MUL" 569 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " * ", OperandStringPseudo(1), "#;") 570 | Case "@not / BCOM" 571 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ~", OperandStringPseudo(0), "#;") 572 | Case "@or / BOR" 573 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " | ", OperandStringPseudo(1), "#;") 574 | Case "@pull / POP" 575 | If OperandAddrMode(0) = EnumAddressMode.NONE Then 576 | pseudoCodeString = String.Concat(StoreStringPseudo, " = stack.pop()#;") 577 | Else 578 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), ".pop()#;") 579 | End If 580 | Case "@random / RANDOM" 581 | pseudoCodeString = String.Concat(StoreStringPseudo, " = random(", OperandStringPseudo(0), ")#;") 582 | Case "@read / READ" 583 | pseudoCodeString = String.Concat(StoreStringPseudo, " = read(", PseudoConcatOperands(0), ")#;") 584 | Case "@read_char / INPUT" 585 | pseudoCodeString = String.Concat(StoreStringPseudo, " = read_char(", PseudoConcatOperands(0), ")#;") 586 | Case "@restore / RESTORE" 587 | Dim sTmp As String = "" 588 | If Not OperandAddrMode(1) = EnumAddressMode.NONE Then sTmp = PseudoConcatOperands(0) 589 | pseudoCodeString = String.Concat(StoreStringPseudo, " = restore(", sTmp, ")#;") 590 | Case "@restore_undo / IRESTORE" 591 | pseudoCodeString = String.Concat(StoreStringPseudo, " = restore_undo(", OperandStringPseudo(0), ")#;") 592 | Case "@save / SAVE" 593 | Dim sTmp As String = "" 594 | If Not OperandAddrMode(1) = EnumAddressMode.NONE Then sTmp = PseudoConcatOperands(0) 595 | pseudoCodeString = String.Concat(StoreStringPseudo, " = save(", sTmp, ")#;") 596 | Case "@save_undo / ISAVE" 597 | pseudoCodeString = String.Concat(StoreStringPseudo, " = save_undo(", OperandStringPseudo(0), ")#;") 598 | Case "@set_font / FONT" 599 | pseudoCodeString = String.Concat(StoreStringPseudo, " = set_font(", PseudoConcatOperands(0), ")#;") 600 | Case "@sub / SUB" 601 | pseudoCodeString = String.Concat(StoreStringPseudo, " = ", OperandStringPseudo(0), " - ", OperandStringPseudo(1), "#;") 602 | End Select 603 | ElseIf Extra = EnumExtra.E_TEXT Then 604 | 'print, PRINTI 605 | 'print_ret, PRINTR 606 | Dim pseudoText As String = Text.Replace("{", "").Replace("}", "") 607 | If pseudoText.Length > 40 Then pseudoText = String.Concat(pseudoText.AsSpan(0, 40), "...") 608 | Select Case OpcodeText 609 | Case "@print / PRINTI" 610 | pseudoCodeString = String.Concat("print ", Chr(34), pseudoText, Chr(34), ";") 611 | Case "@print_ret / PRINTR" 612 | pseudoCodeString = String.Concat("print_ret ", Chr(34), pseudoText, Chr(34), ";") 613 | End Select 614 | ElseIf Extra = EnumExtra.E_NONE Then 615 | ' @buffer_mode / BUFOUT 616 | ' @call_1n / ICALL1 617 | ' @call_2n / ICALL2 618 | ' @call_vn / ICALL 619 | ' @call_vn2 / IXCALL 620 | ' @clear_attr / FCLEAR 621 | ' @copy_table / COPYT 622 | ' @dec / DEC 623 | ' @draw_picture / DISPLAY 624 | ' @encode_text / ZWSTR 625 | ' @erase_line / ERASE 626 | ' @erase_picture / DCLEAR 627 | ' @erase_window / CLEAR 628 | ' @get_cursor / CURGET 629 | ' @inc / INC 630 | ' @input_stream / DIRIN 631 | ' @insert_obj / MOVE 632 | ' @jump / JUMP 633 | ' @mouse_window / MOUSE-LIMIT 634 | ' @move_window / WINPOS 635 | ' @new_line / CRLF 636 | ' @nop / NOOP 637 | ' @output_stream / DIROUT 638 | ' @picture_table / PICSET 639 | ' @pop / FSTACK 640 | ' @pop_stack / FSTACK 641 | ' @print_addr / PRINTB 642 | ' @print_char / PRINTC 643 | ' @print_form / PRINTF 644 | ' @print_num / PRINTN 645 | ' @print_obj / PRINTD 646 | ' @print_paddr / PRINT 647 | ' @print_table / PRINTT 648 | ' @print_unicode / PRINTU 649 | ' @pull / POP 650 | ' @push / PUSH 651 | ' @put_prop / PUTP 652 | ' @put_wind_prop / WINPUT 653 | ' @quit / QUIT 654 | ' @read / READ 655 | ' @read_mouse / MOUSE-INFO 656 | ' @remove_obj / REMOVE 657 | ' @restart / RESTART 658 | ' @ret / RETURN 659 | ' @ret_popped / RSTACK 660 | ' @rfalse / RFALSE 661 | ' @rtrue / RTRUE 662 | ' @scroll_window / SCROLL 663 | ' @set_attr / FSET 664 | ' @set_colour / COLOR 665 | ' @set_cursor / CURSET 666 | ' @set_margins / MARGIN 667 | ' @set_text_style / HLIGHT 668 | ' @set_true_colour / *SET_TRUE_COLOUR* 669 | ' @set_window / SCREEN 670 | ' @show_status / USL 671 | ' @sound_effect / SOUND 672 | ' @split_window / SPLIT 673 | ' @store / SET 674 | ' @storeb / PUTB 675 | ' @storew / PUT 676 | ' @throw / THROW 677 | ' @tokenise / LEX 678 | ' @window_size / WINSIZE 679 | ' @window_style / WINATTR 680 | Select Case OpcodeText 681 | Case "@buffer_mode / BUFOUT" 682 | pseudoCodeString = String.Concat("buffer_mode(", OperandStringPseudo(0), ");") 683 | Case "@call_1n / ICALL1", "@call_2n / ICALL2", "@call_vn / ICALL", "@call_vn2 / IXCALL" 684 | pseudoCodeString = String.Concat(OperandStringPseudo(0), "(", PseudoConcatOperands(1), ");") 685 | Case "@clear_attr / FCLEAR" 686 | pseudoCodeString = String.Concat("give ", OperandStringPseudo(0), " ~", OperandStringPseudo(1), ";") 687 | Case "@copy_table / COPYT" 688 | pseudoCodeString = String.Concat("copy_table(", PseudoConcatOperands, ");") 689 | Case "@dec / DEC" 690 | pseudoCodeString = String.Concat(OperandStringPseudo(0), "--;") 691 | Case "@draw_picture / DISPLAY" 692 | pseudoCodeString = String.Concat("draw_picture(", PseudoConcatOperands, ");") 693 | Case "@encode_text / ZWSTR" 694 | pseudoCodeString = String.Concat("encode_text(", PseudoConcatOperands, ");") 695 | Case "@erase_line / ERASE" 696 | pseudoCodeString = String.Concat("erase_line(", PseudoConcatOperands, ");") 697 | Case "@erase_picture / DCLEAR" 698 | pseudoCodeString = String.Concat("erase_picture(", PseudoConcatOperands, ");") 699 | Case "@erase_window / CLEAR" 700 | pseudoCodeString = String.Concat("erase_window(", OperandStringPseudo(0), ");") 701 | Case "@get_cursor / CURGET" 702 | pseudoCodeString = String.Concat("get_cursor(", OperandStringPseudo(0), ");") 703 | Case "@inc / INC" 704 | pseudoCodeString = String.Concat(OperandStringPseudo(0), "++;") 705 | Case "@input_stream / DIRIN" 706 | pseudoCodeString = String.Concat("input_stream(", OperandStringPseudo(0), ");") 707 | Case "@insert_obj / MOVE" 708 | pseudoCodeString = String.Concat("move ", OperandStringPseudo(0), " to ", OperandStringPseudo(1), ";") 709 | Case "@jump / JUMP" 710 | pseudoCodeString = String.Concat("jump ", OperandStringPseudo(0), ";") 711 | Case "@mouse_window / MOUSE-LIMIT" 712 | pseudoCodeString = String.Concat("mouse_window(", OperandStringPseudo(0), ");") 713 | Case "@move_window / WINPOS" 714 | pseudoCodeString = String.Concat("move_window(", PseudoConcatOperands, ");") 715 | Case "@new_line / CRLF" 716 | pseudoCodeString = "new_line;" 717 | Case "@nop / NOOP" 718 | pseudoCodeString = "nop;" 719 | Case "@output_stream / DIROUT" 720 | pseudoCodeString = String.Concat("output_stream(", PseudoConcatOperands, ");") 721 | Case "@picture_table / PICSET" 722 | pseudoCodeString = String.Concat("picture_table(", OperandStringPseudo(0), ");") 723 | Case "@pop / FSTACK" 724 | pseudoCodeString = "stack.pop();" 725 | Case "@pop_stack / FSTACK" 726 | Dim sTmp As String = "stack" 727 | If Not OperandAddrMode(1) = EnumAddressMode.NONE Then sTmp = OperandStringPseudo(1) 728 | pseudoCodeString = String.Concat(sTmp, ".pop(", OperandStringPseudo(0), ");") 729 | Case "@print_addr / PRINTB" 730 | pseudoCodeString = String.Concat("print_addr(", OperandStringPseudo(0), ");") 731 | Case "@print_char / PRINTC" 732 | pseudoCodeString = String.Concat("print_char(", OperandStringPseudo(0), ");") 733 | Case "@print_form / PRINTF" 734 | pseudoCodeString = String.Concat("print_form(", OperandStringPseudo(0), ");") 735 | Case "@print_num / PRINTN" 736 | pseudoCodeString = String.Concat("print_num(", OperandStringPseudo(0), ");") 737 | Case "@print_obj / PRINTD" 738 | pseudoCodeString = String.Concat("print_obj(", OperandStringPseudo(0), ");") 739 | Case "@print_paddr / PRINT" 740 | Dim pseudoText As String = OperandStringPseudo(0) 741 | If pseudoText.Contains(Chr(34)) Then 742 | pseudoText = pseudoText.Substring(pseudoText.IndexOf(Chr(34))) 743 | pseudoText = pseudoText.Replace("{", "").Replace("}", "").Replace(Chr(34), "") 744 | If pseudoText.Length > 40 Then pseudoText = String.Concat(pseudoText.AsSpan(0, 40), "...") 745 | pseudoText = String.Concat(Chr(34), pseudoText, Chr(34)) 746 | End If 747 | pseudoCodeString = String.Concat("print_paddr ", pseudoText, ";") 748 | Case "@print_table / PRINTT" 749 | pseudoCodeString = String.Concat("print_table(", PseudoConcatOperands, ");") 750 | Case "@print_unicode / PRINTU" 751 | pseudoCodeString = String.Concat("print_unicode(", OperandStringPseudo(0), ");") 752 | Case "@pull / POP" 753 | pseudoCodeString = String.Concat(OperandStringPseudo(0), " = stack.pop()#;") 754 | Case "@push / PUSH" 755 | pseudoCodeString = String.Concat("stack.push(", OperandStringPseudo(0), ");") 756 | Case "@put_prop / PUTP" 757 | pseudoCodeString = String.Concat(OperandStringPseudo(0), ".", OperandStringPseudo(1), " = ", OperandStringPseudo(2), ";") 758 | Case "@put_wind_prop / WINPUT" 759 | pseudoCodeString = String.Concat("put_wind_prop(", PseudoConcatOperands, ");") 760 | Case "@quit / QUIT" 761 | pseudoCodeString = "quit;" 762 | Case "@read / READ" 763 | pseudoCodeString = String.Concat("read(", PseudoConcatOperands, ");") 764 | Case "@read_mouse / MOUSE-INFO" 765 | pseudoCodeString = String.Concat("read_mouse(", OperandStringPseudo(0), ");") 766 | Case "@remove_obj / REMOVE" 767 | pseudoCodeString = String.Concat("remove ", OperandStringPseudo(0), ";") 768 | Case "@restart / RESTART" 769 | pseudoCodeString = "restart;" 770 | Case "@ret / RETURN" 771 | pseudoCodeString = String.Concat("return ", OperandStringPseudo(0), ";") 772 | Case "@ret_popped / RSTACK" 773 | pseudoCodeString = "return stack.pop();" 774 | Case "@rfalse / RFALSE" 775 | pseudoCodeString = "rfalse;" 776 | Case "@rtrue / RTRUE" 777 | pseudoCodeString = "rtrue;" 778 | Case "@scroll_window / SCROLL" 779 | pseudoCodeString = String.Concat("scroll_window(", PseudoConcatOperands, ");") 780 | Case "@set_attr / FSET" 781 | pseudoCodeString = String.Concat("give ", OperandStringPseudo(0), " ", OperandStringPseudo(1), ";") 782 | Case "@set_colour / COLOR" 783 | pseudoCodeString = String.Concat("set_colour(", PseudoConcatOperands, ");") 784 | Case "@set_cursor / CURSET" 785 | pseudoCodeString = String.Concat("set_cursor(", PseudoConcatOperands, ");") 786 | Case "@set_margins / MARGIN" 787 | pseudoCodeString = String.Concat("set_margins(", PseudoConcatOperands, ");") 788 | Case "@set_text_style / HLIGHT" 789 | pseudoCodeString = String.Concat("set_text_style(", OperandStringPseudo(0), ");") 790 | Case "@set_true_colour / *SET_TRUE_COLOUR*" 791 | pseudoCodeString = String.Concat("set_true_colour(", PseudoConcatOperands, ");") 792 | Case "@set_window / SCREEN" 793 | pseudoCodeString = String.Concat("set_window(", OperandStringPseudo(0), ");") 794 | Case "@show_status / USL" 795 | pseudoCodeString = "show_status;" 796 | Case "@sound_effect / SOUND" 797 | pseudoCodeString = String.Concat("sound_effect(", PseudoConcatOperands, ");") 798 | Case "@split_window / SPLIT" 799 | pseudoCodeString = String.Concat("split_window(", OperandStringPseudo(0), ");") 800 | Case "@store / SET" 801 | pseudoCodeString = String.Concat(OperandStringPseudo(0), " = ", OperandStringPseudo(1), "#;") 802 | Case "@storeb / PUTB" 803 | pseudoCodeString = String.Concat(OperandStringPseudo(0), "->", OperandStringPseudo(1), " = ", OperandStringPseudo(2), ";") 804 | Case "@storew / PUT" 805 | pseudoCodeString = String.Concat(OperandStringPseudo(0), "-->", OperandStringPseudo(1), " = ", OperandStringPseudo(2), ";") 806 | Case "@throw / THROW" 807 | pseudoCodeString = String.Concat("throw(", PseudoConcatOperands, ");") 808 | Case "@tokenise / LEX" 809 | pseudoCodeString = String.Concat("tokenise(", PseudoConcatOperands, ");") 810 | Case "@window_size / WINSIZE" 811 | pseudoCodeString = String.Concat("window_size(", PseudoConcatOperands, ");") 812 | Case "@window_style / WINATTR" 813 | pseudoCodeString = String.Concat("window_style(", PseudoConcatOperands, ");") 814 | End Select 815 | End If 816 | pseudoCodeString = pseudoCodeString.Replace("sp = ", "stack.push(") 817 | If pseudoCodeString.Contains("stack.push") Then pseudoCodeString = pseudoCodeString.Replace("#;", ");") Else pseudoCodeString = pseudoCodeString.Replace("#;", ";") 818 | If stackPeek Then pseudoCodeString = pseudoCodeString.Replace("if (sp", "if (stack.peek()") 819 | pseudoCodeString = pseudoCodeString.Replace("sp", "stack.pop()") 820 | 821 | Return pseudoCodeString 822 | End Function 823 | 824 | Private Shared Function OperandDescription(operandValue As Integer) As String 825 | Select Case operandValue 826 | Case &H0 827 | Return "large constant (long immediate)" 828 | Case &H1 829 | Return "constant (immediate)" 830 | Case &H2 831 | Return "variable" 832 | Case Else 833 | Return "no more operands" 834 | End Select 835 | End Function 836 | 837 | Private Shared Function VariableDescription(variableValue As Integer) As String 838 | If variableValue = 0 Then 839 | Return "SP" 840 | ElseIf variableValue < 16 Then 841 | Return "L" & (variableValue - 1).ToString() 842 | Else 843 | Return "G" & (variableValue - 16).ToString() 844 | End If 845 | End Function 846 | 847 | Private Function PseudoBranchText() As String 848 | Select Case BranchAddr 849 | Case 0 850 | Return "rfalse" 851 | Case 1 852 | Return "rtrue" 853 | Case Else 854 | Return "jump 0x" & BranchAddr.ToString("X4") 855 | End Select 856 | End Function 857 | Private Function PseudoConcatOperands(Optional startIndex As Integer = 0, Optional slutIndex As Integer = 3, Optional text As String = ", ") As String 858 | Dim sTmp As String = OperandStringPseudo(startIndex) 859 | For i As Integer = startIndex + 1 To slutIndex 860 | If Not OperandAddrMode(i) = EnumAddressMode.NONE Then sTmp &= text & OperandStringPseudo(i) 861 | Next 862 | Return sTmp 863 | End Function 864 | 865 | End Class 866 | 867 | Public Function DecodeRoutine(piAtAddress As Integer, gameData() As Byte, psAbbreviations() As String, silent As Boolean, zcodeSyntax As Integer, 868 | pValidStringList As List(Of StringData), pValidRoutineList As List(Of RoutineData), pDictEntriesList As DictionaryEntries, 869 | pAlpabet() As String, initialPC As Integer, propertyNumberMin As Integer, propertyNumberMax As Integer, 870 | showAbbrevsInsertionPoints As Boolean, inlineStringsList As List(Of InlineString), showZCodeVerbose As Boolean) As Integer 871 | startAddress = piAtAddress 872 | byteGame = gameData 873 | PC = piAtAddress 874 | high_pc = PC 875 | ZVersion = byteGame(0) 876 | sAbbreviations = psAbbreviations 877 | bSilent = silent 878 | syntax = zcodeSyntax 879 | validStringList = pValidStringList 880 | validRoutineList = pValidRoutineList 881 | DictEntriesList = pDictEntriesList 882 | alphabet = pAlpabet 883 | propertyMin = propertyNumberMin 884 | propertyMax = propertyNumberMax 885 | showAbbrevsInsertion = showAbbrevsInsertionPoints 886 | inlineStrings = inlineStringsList 887 | bShowZCodeVerbose = showZCodeVerbose 888 | 889 | If PC > byteGame.Length Then Return -1 890 | 891 | localsCount = byteGame(PC) 892 | 893 | If localsCount > 15 Then Return -1 ' Not a valid routine startIndex address 894 | 895 | If Not bSilent Then 896 | If initialPC - 1 = PC Then 897 | Console.Write("Main routine: 0x{0:X5}", PC) 898 | Else 899 | Console.Write("Routine: 0x{0:X5}", PC) 900 | End If 901 | Dim oRoutineData As RoutineData = validRoutineList.Find(Function(c) c.entryPoint = PC) 902 | If oRoutineData IsNot Nothing Then 903 | Dim first As Boolean = True 904 | For Each callFrom As String In oRoutineData.callsFrom 905 | If first Then Console.Write(Space(15)) Else Console.Write(Space(31)) 906 | If callFrom.Length > 97 Then 907 | Console.WriteLine(callFrom.Substring(0, 98)) 908 | Dim sRest As String = callFrom.Substring(98).Trim 909 | Do 910 | If sRest.Length > 71 Then 911 | Console.WriteLine("{0}{1}", Space(57), sRest.Substring(0, 72).Trim) 912 | sRest = sRest.Substring(72).Trim 913 | Else 914 | Console.WriteLine("{0}{1}", Space(57), sRest) 915 | sRest = "" 916 | End If 917 | Loop Until sRest = "" 918 | Else 919 | Console.WriteLine(callFrom) 920 | End If 921 | first = False 922 | Next 923 | If oRoutineData.callsFrom.Count = 0 Then Console.WriteLine() 924 | End If 925 | If ZVersion > 4 Then 926 | If localsCount = 0 Then Console.WriteLine("{0:X5} {1:X2} No locals", PC, localsCount) 927 | If localsCount = 1 Then 928 | Console.WriteLine("{0:X5} {1:X2} 1 local", PC, localsCount) 929 | Console.Write(Space(31)) 930 | Console.WriteLine("({0})", TextVariable(1, syntax)) 931 | End If 932 | If localsCount > 1 Then 933 | Console.WriteLine("{0:X5} {1:X2} {2} locals", PC, localsCount, localsCount) 934 | Console.Write(Space(31) & "(") 935 | For i = 0 To localsCount - 1 936 | Console.Write("{0}", TextVariable(i + 1, syntax)) 937 | If i < localsCount - 1 Then Console.Write(" ") 938 | Next 939 | Console.WriteLine(")") 940 | End If 941 | Else 942 | If localsCount = 0 Then Console.WriteLine("{0:X5} {1:X2} No locals", PC, localsCount) 943 | If localsCount = 1 Then Console.WriteLine("{0:X5} {1:X2} 1 local", PC, localsCount) 944 | If localsCount > 1 Then Console.WriteLine("{0:X5} {1:X2} {2} locals", PC, localsCount, localsCount) 945 | If localsCount > 0 Then 946 | Console.Write("{0:X5} ", PC + 1) 947 | Dim count As Integer = 0 948 | Dim text As String = " " 949 | For i = 0 To localsCount - 1 950 | Console.Write("{0:X2} {1:X2} ", byteGame(PC + i * 2 + 1), byteGame(PC + i * 2 + 2)) 951 | Dim number As Integer = byteGame(PC + i * 2 + 1) * 256 + byteGame(PC + i * 2 + 2) 952 | If syntax = 1 Then text = text & TextVariable(i + 1, syntax) & "=0x" & number.ToString("x4") & " " Else text = text & TextVariable(i + 1, syntax) & "=0x" & number.ToString("X4") & " " 953 | count += 1 954 | If count = 4 Then 955 | count = 0 956 | Console.WriteLine(text) 957 | Console.Write(Space(6)) 958 | text = " " 959 | End If 960 | Next 961 | If count > 0 Then 962 | Console.Write(Space(6 * (4 - count))) 963 | Console.WriteLine(text) 964 | End If 965 | End If 966 | End If 967 | Console.WriteLine() 968 | End If 969 | 970 | If ZVersion < 5 Then PC += localsCount * 2 971 | 972 | PC += 1 973 | 974 | Dim oDecodeResult As DecodeResult 975 | Dim high_routine_old As Integer = highest_routine 976 | Dim low_routine_old As Integer = lowest_routine 977 | Dim lowest_string_old As Integer = lowest_string 978 | Dim highest_global_old As Integer = highest_global 979 | 980 | callsTo.Clear() 981 | Do 982 | oDecodeResult = DecodeCode(PC) 983 | PC = oDecodeResult.nextPC 984 | 985 | If oDecodeResult.status = EnumStatus.BAD_OPCODE Or oDecodeResult.status = EnumStatus.BAD_ENTRY Then 986 | highest_routine = high_routine_old 987 | lowest_routine = low_routine_old 988 | lowest_string = lowest_string_old 989 | highest_global = highest_global_old 990 | For Each x As Integer In usedGlobals 991 | If x > highest_global Or x < 0 Then usedGlobals.Remove(x) 992 | Next 993 | callsTo.Clear() 994 | Return -1 995 | End If 996 | 997 | Loop Until oDecodeResult.status = EnumStatus.END_OF_ROUTINE 998 | 999 | Return PC 1000 | End Function 1001 | 1002 | Private Function DecodeCode(piAtAddress As Integer) As DecodeResult 1003 | Dim iPC As Integer = piAtAddress 1004 | 1005 | 'If piAtAddress > byteGame.Length - 10 Then 1006 | ' Return New DecodeResult With {.status = EnumStatus.BAD_ENTRY} 1007 | 'End If 1008 | 1009 | Try 1010 | Dim oOpcode As New Opcode With { 1011 | .Address = piAtAddress, 1012 | .Code = byteGame(iPC), 1013 | .OpcodeClass = EnumOpcodeClass.ZERO_OPERAND 1014 | } 1015 | 1016 | If ZVersion > 4 And oOpcode.Code = 190 Then ' This is the EXTOP opcode 1017 | oOpcode.OpcodeClass = EnumOpcodeClass.EXTENDED_OPERAND 1018 | iPC += 1 1019 | oOpcode.Code = byteGame(iPC) 1020 | oOpcode.ExtModeByte = byteGame(iPC + 1) 1021 | Else 1022 | If oOpcode.Code < 128 Then 1023 | oOpcode.OpcodeClass = EnumOpcodeClass.TWO_OPERAND 1024 | ElseIf oOpcode.Code < 176 Then 1025 | oOpcode.OpcodeClass = EnumOpcodeClass.ONE_OPERAND 1026 | ElseIf oOpcode.Code < 192 Then 1027 | oOpcode.OpcodeClass = EnumOpcodeClass.ZERO_OPERAND 1028 | Else 1029 | oOpcode.OpcodeClass = EnumOpcodeClass.VARIABLE_OPERAND 1030 | End If 1031 | End If 1032 | 1033 | ' decode instruction 1034 | Dim iCode As Integer = oOpcode.Code 1035 | Select Case oOpcode.OpcodeClass 1036 | Case EnumOpcodeClass.EXTENDED_OPERAND 1037 | iCode = iCode And &H3F 1038 | Select Case iCode 1039 | Case &H0 : Return DecodeOperands(oOpcode, "SAVE", "SAVE", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1040 | Case &H1 : Return DecodeOperands(oOpcode, "RESTORE", "RESTORE", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1041 | Case &H2 : Return DecodeOperands(oOpcode, "LOG_SHIFT", "SHIFT", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1042 | Case &H3 : Return DecodeOperands(oOpcode, "ART_SHIFT", "ASHIFT", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1043 | Case &H4 : Return DecodeOperands(oOpcode, "SET_FONT", "FONT", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1044 | Case &H5 : Return DecodeOperands(oOpcode, "DRAW_PICTURE", "DISPLAY", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1045 | Case &H6 : Return DecodeOperands(oOpcode, "PICTURE_DATA", "PICINF", EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1046 | Case &H7 : Return DecodeOperands(oOpcode, "ERASE_PICTURE", "DCLEAR", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1047 | Case &H8 : Return DecodeOperands(oOpcode, "SET_MARGINS", "MARGIN", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1048 | Case &H9 : Return DecodeOperands(oOpcode, "SAVE_UNDO", "ISAVE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1049 | Case &HA : Return DecodeOperands(oOpcode, "RESTORE_UNDO", "IRESTORE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1050 | Case &H10 : Return DecodeOperands(oOpcode, "MOVE_WINDOW", "WINPOS", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1051 | Case &H11 : Return DecodeOperands(oOpcode, "WINDOW_SIZE", "WINSIZE", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1052 | Case &H12 : Return DecodeOperands(oOpcode, "WINDOW_STYLE", "WINATTR", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1053 | Case &H13 : Return DecodeOperands(oOpcode, "GET_WIND_PROP", "WINGET", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1054 | Case &H14 : Return DecodeOperands(oOpcode, "SCROLL_WINDOW", "SCROLL", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1055 | Case &H15 : Return DecodeOperands(oOpcode, "POP_STACK", "FSTACK", EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1056 | Case &H16 : Return DecodeOperands(oOpcode, "READ_MOUSE", "MOUSE-INFO", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1057 | Case &H17 : Return DecodeOperands(oOpcode, "MOUSE_WINDOW", "MOUSE-LIMIT", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1058 | Case &H18 : Return DecodeOperands(oOpcode, "PUSH_STACK", "XPUSH", EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1059 | Case &H19 : Return DecodeOperands(oOpcode, "PUT_WIND_PROP", "WINPUT", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1060 | Case &H1A : Return DecodeOperands(oOpcode, "PRINT_FORM", "PRINTF", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1061 | Case &H1B : Return DecodeOperands(oOpcode, "MAKE_MENU", "MENU", EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1062 | Case &H1C : Return DecodeOperands(oOpcode, "PICTURE_TABLE", "PICSET", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1063 | Case Else 1064 | Select Case ZVersion 1065 | Case 5, 7, 8 1066 | Select Case iCode 1067 | Case &HB : Return DecodeOperands(oOpcode, "PRINT_UNICODE", "PRINTU", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 'Added in standard 1.0 1068 | Case &HC : Return DecodeOperands(oOpcode, "CHECK_UNICODE", "CHECKU", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 'Added in standard 1.0 1069 | Case &HD : Return DecodeOperands(oOpcode, "SET_TRUE_COLOUR", "*SET_TRUE_COLOUR*", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 'Added in standard 1.1, not available in Zapf 1070 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1071 | End Select 1072 | Case 6 1073 | Select Case iCode 1074 | Case &HB : Return DecodeOperands(oOpcode, "PRINT_UNICODE", "PRINTU", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 'Added in standard 1.0 1075 | Case &HC : Return DecodeOperands(oOpcode, "CHECK_UNICODE", "CHECKU", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 'Added in standard 1.0 1076 | Case &HD : Return DecodeOperands(oOpcode, "SET_TRUE_COLOUR", "*SET_TRUE_COLOUR*", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 'Added in standard 1.1, not available in Zapf 1077 | Case &H1D : Return DecodeOperands(oOpcode, "BUFFER_SCREEN", "*BUFFER_SCREEN*", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 'Added in standard 1.1, not available in Zapf 1078 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1079 | End Select 1080 | End Select 1081 | End Select 1082 | Case EnumOpcodeClass.TWO_OPERAND, EnumOpcodeClass.VARIABLE_OPERAND 1083 | If oOpcode.OpcodeClass = EnumOpcodeClass.TWO_OPERAND Then iCode = iCode And &H1F Else iCode = iCode And &H3F 1084 | Select Case iCode 1085 | Case &H1 : Return DecodeOperands(oOpcode, "JE", "EQUAL?", EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1086 | Case &H2 : Return DecodeOperands(oOpcode, "JL", "LESS?", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1087 | Case &H3 : Return DecodeOperands(oOpcode, "JG", "GRTR?", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1088 | Case &H4 : Return DecodeOperands(oOpcode, "DEC_CHK", "DLESS?", EnumOperand.P_VAR, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1089 | Case &H5 : Return DecodeOperands(oOpcode, "INC_CHK", "IGRTR?", EnumOperand.P_VAR, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1090 | Case &H6 : Return DecodeOperands(oOpcode, "JIN", "IN?", EnumOperand.P_OBJECT, EnumOperand.P_OBJECT, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1091 | Case &H7 : Return DecodeOperands(oOpcode, "TEST", "BTST", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1092 | Case &H8 : Return DecodeOperands(oOpcode, "OR", "BOR", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1093 | Case &H9 : Return DecodeOperands(oOpcode, "AND", "BAND", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1094 | Case &HA : Return DecodeOperands(oOpcode, "TEST_ATTR", "FSET?", EnumOperand.P_OBJECT, EnumOperand.P_ATTRNUM, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1095 | Case &HB : Return DecodeOperands(oOpcode, "SET_ATTR", "FSET", EnumOperand.P_OBJECT, EnumOperand.P_ATTRNUM, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1096 | Case &HC : Return DecodeOperands(oOpcode, "CLEAR_ATTR", "FCLEAR", EnumOperand.P_OBJECT, EnumOperand.P_ATTRNUM, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1097 | Case &HD : Return DecodeOperands(oOpcode, "STORE", "SET", EnumOperand.P_VAR, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1098 | Case &HE : Return DecodeOperands(oOpcode, "INSERT_OBJ", "MOVE", EnumOperand.P_OBJECT, EnumOperand.P_OBJECT, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1099 | Case &HF : Return DecodeOperands(oOpcode, "LOADW", "GET", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1100 | Case &H10 : Return DecodeOperands(oOpcode, "LOADB", "GETB", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1101 | Case &H11 : Return DecodeOperands(oOpcode, "GET_PROP", "GETP", EnumOperand.P_OBJECT, EnumOperand.P_PROPNUM, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1102 | Case &H12 : Return DecodeOperands(oOpcode, "GET_PROP_ADDR", "GETPT", EnumOperand.P_OBJECT, EnumOperand.P_PROPNUM, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1103 | Case &H13 : Return DecodeOperands(oOpcode, "GET_NEXT_PROP", "NEXTP", EnumOperand.P_OBJECT, EnumOperand.P_PROPNUM, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1104 | 'TXD have LOW_ADDR for operands, why? 1105 | 'Case &H14 : Return DecodeOperands(oOpcode, "ADD", "ADD", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1106 | Case &H14 : Return DecodeOperands(oOpcode, "ADD", "ADD", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1107 | Case &H15 : Return DecodeOperands(oOpcode, "SUB", "SUB", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1108 | Case &H16 : Return DecodeOperands(oOpcode, "MUL", "MUL", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1109 | Case &H17 : Return DecodeOperands(oOpcode, "DIV", "DIV", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1110 | Case &H18 : Return DecodeOperands(oOpcode, "MOD", "MOD", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1111 | Case &H21 : Return DecodeOperands(oOpcode, "STOREW", "PUT", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1112 | Case &H22 : Return DecodeOperands(oOpcode, "STOREB", "PUTB", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1113 | Case &H23 : Return DecodeOperands(oOpcode, "PUT_PROP", "PUTP", EnumOperand.P_OBJECT, EnumOperand.P_PROPNUM, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1114 | Case &H25 : Return DecodeOperands(oOpcode, "PRINT_CHAR", "PRINTC", EnumOperand.P_PCHAR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1115 | Case &H26 : Return DecodeOperands(oOpcode, "PRINT_NUM", "PRINTN", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1116 | Case &H27 : Return DecodeOperands(oOpcode, "RANDOM", "RANDOM", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1117 | Case &H28 : Return DecodeOperands(oOpcode, "PUSH", "PUSH", EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1118 | Case &H2A : Return DecodeOperands(oOpcode, "SPLIT_WINDOW", "SPLIT", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1119 | Case &H2B : Return DecodeOperands(oOpcode, "SET_WINDOW", "SCREEN", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1120 | Case &H33 : Return DecodeOperands(oOpcode, "OUTPUT_STREAM", "DIROUT", EnumOperand.P_PATTR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1121 | Case &H34 : Return DecodeOperands(oOpcode, "INPUT_STREAM", "DIRIN", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1122 | Case &H35 : Return DecodeOperands(oOpcode, "SOUND_EFFECT", "SOUND", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_ROUTINE, EnumExtra.E_NONE, EnumType.T_PLAIN) 1123 | Case Else 1124 | Select Case ZVersion 1125 | Case 1, 2, 3 1126 | Select Case iCode 1127 | Case &H20 : Return DecodeOperands(oOpcode, "CALL", "CALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_STORE, EnumType.T_CALL) 1128 | Case &H24 : Return DecodeOperands(oOpcode, "READ", "READ", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1129 | Case &H29 : Return DecodeOperands(oOpcode, "PULL", "POP", EnumOperand.P_VAR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1130 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1131 | End Select 1132 | Case 4 1133 | Select Case iCode 1134 | Case &H19 : Return DecodeOperands(oOpcode, "CALL_2S", "CALL2", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_CALL) 1135 | Case &H20 : Return DecodeOperands(oOpcode, "CALL_VS", "CALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_STORE, EnumType.T_CALL) 1136 | Case &H24 : Return DecodeOperands(oOpcode, "READ", "READ", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_ROUTINE, EnumExtra.E_NONE, EnumType.T_PLAIN) 1137 | Case &H29 : Return DecodeOperands(oOpcode, "PULL", "POP", EnumOperand.P_VAR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1138 | Case &H2C : Return DecodeOperands(oOpcode, "CALL_VS2", "XCALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_STORE, EnumType.T_CALL) 1139 | Case &H2D : Return DecodeOperands(oOpcode, "ERASE_WINDOW", "CLEAR", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1140 | Case &H2E : Return DecodeOperands(oOpcode, "ERASE_LINE", "ERASE", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1141 | Case &H2F : Return DecodeOperands(oOpcode, "SET_CURSOR", "CURSET", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1142 | Case &H31 : Return DecodeOperands(oOpcode, "SET_TEXT_STYLE", "HLIGHT", EnumOperand.P_VATTR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1143 | Case &H32 : Return DecodeOperands(oOpcode, "BUFFER_MODE", "BUFOUT", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1144 | Case &H36 : Return DecodeOperands(oOpcode, "READ_CHAR", "INPUT", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_ROUTINE, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1145 | Case &H37 : Return DecodeOperands(oOpcode, "SCAN_TABLE", "INTBL?", EnumOperand.P_ANYTHING, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumExtra.E_BOTH, EnumType.T_PLAIN) 1146 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1147 | End Select 1148 | Case 5, 7, 8 1149 | Select Case iCode 1150 | Case &H19 : Return DecodeOperands(oOpcode, "CALL_2S", "CALL2", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_CALL) 1151 | Case &H1A : Return DecodeOperands(oOpcode, "CALL_2N", "ICALL2", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_CALL) 1152 | Case &H1B : Return DecodeOperands(oOpcode, "SET_COLOUR", "COLOR", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1153 | Case &H1C : Return DecodeOperands(oOpcode, "THROW", "THROW", EnumOperand.P_ANYTHING, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) ' This is a valid opcode in v 5- 1154 | Case &H20 : Return DecodeOperands(oOpcode, "CALL_VS", "CALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_STORE, EnumType.T_CALL) 1155 | Case &H24 : Return DecodeOperands(oOpcode, "READ", "READ", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_ROUTINE, EnumExtra.E_STORE, EnumType.T_PLAIN) 1156 | Case &H29 : Return DecodeOperands(oOpcode, "PULL", "POP", EnumOperand.P_VAR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1157 | Case &H2C : Return DecodeOperands(oOpcode, "CALL_VS2", "XCALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_STORE, EnumType.T_CALL) 1158 | Case &H2D : Return DecodeOperands(oOpcode, "ERASE_WINDOW", "CLEAR", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1159 | Case &H2E : Return DecodeOperands(oOpcode, "ERASE_LINE", "ERASE", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1160 | Case &H2F : Return DecodeOperands(oOpcode, "SET_CURSOR", "CURSET", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1161 | Case &H30 : Return DecodeOperands(oOpcode, "GET_CURSOR", "CURGET", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1162 | Case &H31 : Return DecodeOperands(oOpcode, "SET_TEXT_STYLE", "HLIGHT", EnumOperand.P_VATTR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1163 | Case &H32 : Return DecodeOperands(oOpcode, "BUFFER_MODE", "BUFOUT", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1164 | Case &H36 : Return DecodeOperands(oOpcode, "READ_CHAR", "INPUT", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_ROUTINE, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1165 | Case &H37 : Return DecodeOperands(oOpcode, "SCAN_TABLE", "INTBL?", EnumOperand.P_ANYTHING, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumExtra.E_BOTH, EnumType.T_PLAIN) 1166 | Case &H38 : Return DecodeOperands(oOpcode, "NOT", "BCOM", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1167 | Case &H39 : Return DecodeOperands(oOpcode, "CALL_VN", "ICALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_NONE, EnumType.T_CALL) 1168 | Case &H3A : Return DecodeOperands(oOpcode, "CALL_VN2", "IXCALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_NONE, EnumType.T_CALL) 1169 | Case &H3B : Return DecodeOperands(oOpcode, "TOKENISE", "LEX", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumExtra.E_NONE, EnumType.T_PLAIN) 1170 | Case &H3C : Return DecodeOperands(oOpcode, "ENCODE_TEXT", "ZWSTR", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumExtra.E_NONE, EnumType.T_PLAIN) 1171 | Case &H3D : Return DecodeOperands(oOpcode, "COPY_TABLE", "COPYT", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1172 | Case &H3E : Return DecodeOperands(oOpcode, "PRINT_TABLE", "PRINTT", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumExtra.E_NONE, EnumType.T_PLAIN) 1173 | Case &H3F : Return DecodeOperands(oOpcode, "CHECK_ARG_COUNT", "ASSIGNED?", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1174 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1175 | End Select 1176 | Case 6 1177 | Select Case iCode 1178 | Case &H19 : Return DecodeOperands(oOpcode, "CALL_2S", "CALL2", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_CALL) 1179 | Case &H1A : Return DecodeOperands(oOpcode, "CALL_2N", "ICALL2", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_CALL) 1180 | Case &H1B : Return DecodeOperands(oOpcode, "SET_COLOUR", "COLOR", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1181 | Case &H1C : Return DecodeOperands(oOpcode, "THROW", "THROW", EnumOperand.P_ANYTHING, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1182 | Case &H20 : Return DecodeOperands(oOpcode, "CALL_VS", "CALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_STORE, EnumType.T_CALL) 1183 | Case &H24 : Return DecodeOperands(oOpcode, "READ", "READ", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_ROUTINE, EnumExtra.E_STORE, EnumType.T_PLAIN) 1184 | Case &H29 : Return DecodeOperands(oOpcode, "PULL", "POP", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1185 | Case &H2C : Return DecodeOperands(oOpcode, "CALL_VS2", "XCALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_STORE, EnumType.T_CALL) 1186 | Case &H2D : Return DecodeOperands(oOpcode, "ERASE_WINDOW", "CLEAR", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1187 | Case &H2E : Return DecodeOperands(oOpcode, "ERASE_LINE", "ERASE", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1188 | Case &H2F : Return DecodeOperands(oOpcode, "SET_CURSOR", "CURSET", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1189 | Case &H30 : Return DecodeOperands(oOpcode, "GET_CURSOR", "CURGET", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1190 | Case &H31 : Return DecodeOperands(oOpcode, "SET_TEXT_STYLE", "HLIGHT", EnumOperand.P_VATTR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1191 | Case &H32 : Return DecodeOperands(oOpcode, "BUFFER_MODE", "BUFOUT", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1192 | Case &H36 : Return DecodeOperands(oOpcode, "READ_CHAR", "INPUT", EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_ROUTINE, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1193 | Case &H37 : Return DecodeOperands(oOpcode, "SCAN_TABLE", "INTBL?", EnumOperand.P_ANYTHING, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumExtra.E_BOTH, EnumType.T_PLAIN) 1194 | Case &H38 : Return DecodeOperands(oOpcode, "NOT", "BCOM", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1195 | Case &H39 : Return DecodeOperands(oOpcode, "CALL_VN", "ICALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_NONE, EnumType.T_CALL) 1196 | Case &H3A : Return DecodeOperands(oOpcode, "CALL_VN2", "IXCALL", EnumOperand.P_ROUTINE, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumOperand.P_ANYTHING, EnumExtra.E_NONE, EnumType.T_CALL) 1197 | Case &H3B : Return DecodeOperands(oOpcode, "TOKENISE", "LEX", EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumExtra.E_NONE, EnumType.T_PLAIN) 1198 | Case &H3C : Return DecodeOperands(oOpcode, "ENCODE_TEXT", "ZWSTR", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumExtra.E_NONE, EnumType.T_PLAIN) 1199 | Case &H3D : Return DecodeOperands(oOpcode, "COPY_TABLE", "COPYT", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1200 | Case &H3E : Return DecodeOperands(oOpcode, "PRINT_TABLE", "PRINTT", EnumOperand.P_LOW_ADDR, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumOperand.P_NUMBER, EnumExtra.E_NONE, EnumType.T_PLAIN) 1201 | Case &H3F : Return DecodeOperands(oOpcode, "CHECK_ARG_COUNT", "ASSIGNED?", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1202 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1203 | End Select 1204 | End Select 1205 | End Select 1206 | Case EnumOpcodeClass.ONE_OPERAND 1207 | iCode = iCode And &HF 1208 | Select Case iCode 1209 | Case &H0 : Return DecodeOperands(oOpcode, "JZ", "ZERO?", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1210 | Case &H1 : Return DecodeOperands(oOpcode, "GET_SIBLING", "NEXT?", EnumOperand.P_OBJECT, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BOTH, EnumType.T_PLAIN) 1211 | Case &H2 : Return DecodeOperands(oOpcode, "GET_CHILD", "FIRST?", EnumOperand.P_OBJECT, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BOTH, EnumType.T_PLAIN) 1212 | Case &H3 : Return DecodeOperands(oOpcode, "GET_PARENT", "LOC", EnumOperand.P_OBJECT, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1213 | Case &H4 : Return DecodeOperands(oOpcode, "GET_PROP_LEN", "PTSIZE", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1214 | Case &H5 : Return DecodeOperands(oOpcode, "INC", "INC", EnumOperand.P_VAR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1215 | Case &H6 : Return DecodeOperands(oOpcode, "DEC", "DEC", EnumOperand.P_VAR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1216 | Case &H7 : Return DecodeOperands(oOpcode, "PRINT_ADDR", "PRINTB", EnumOperand.P_LOW_ADDR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1217 | Case &H9 : Return DecodeOperands(oOpcode, "REMOVE_OBJ", "REMOVE", EnumOperand.P_OBJECT, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1218 | Case &HA : Return DecodeOperands(oOpcode, "PRINT_OBJ", "PRINTD", EnumOperand.P_OBJECT, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1219 | Case &HB : Return DecodeOperands(oOpcode, "RET", "RETURN", EnumOperand.P_ANYTHING, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_RETURN) 1220 | Case &HC : Return DecodeOperands(oOpcode, "JUMP", "JUMP", EnumOperand.P_LABEL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_RETURN) 1221 | Case &HD : Return DecodeOperands(oOpcode, "PRINT_PADDR", "PRINT", EnumOperand.P_STATIC, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1222 | Case &HE : Return DecodeOperands(oOpcode, "LOAD", "VALUE", EnumOperand.P_VAR, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1223 | Case Else 1224 | Select Case ZVersion 1225 | Case 1, 2, 3 1226 | Select Case iCode 1227 | Case &HF : Return DecodeOperands(oOpcode, "NOT", "BCOM", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1228 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1229 | End Select 1230 | Case 4 1231 | Select Case iCode 1232 | Case &H8 : Return DecodeOperands(oOpcode, "CALL_1S", "CALL1", EnumOperand.P_ROUTINE, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_CALL) 1233 | Case &HF : Return DecodeOperands(oOpcode, "NOT", "BCOM", EnumOperand.P_NUMBER, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1234 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1235 | End Select 1236 | Case 5, 6, 7, 8 1237 | Select Case iCode 1238 | Case &H8 : Return DecodeOperands(oOpcode, "CALL_1S", "CALL1", EnumOperand.P_ROUTINE, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_CALL) 1239 | Case &HF : Return DecodeOperands(oOpcode, "CALL_1N", "ICALL1", EnumOperand.P_ROUTINE, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_CALL) 1240 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1241 | End Select 1242 | End Select 1243 | End Select 1244 | Case EnumOpcodeClass.ZERO_OPERAND 1245 | iCode = iCode And &HF 1246 | Select Case iCode 1247 | Case &H0 : Return DecodeOperands(oOpcode, "RTRUE", "RTRUE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_RETURN) 1248 | Case &H1 : Return DecodeOperands(oOpcode, "RFALSE", "RFALSE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_RETURN) 1249 | Case &H2 : Return DecodeOperands(oOpcode, "PRINT", "PRINTI", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_TEXT, EnumType.T_PLAIN) 1250 | Case &H3 : Return DecodeOperands(oOpcode, "PRINT_RET", "PRINTR", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_TEXT, EnumType.T_RETURN) 1251 | Case &H4 : Return DecodeOperands(oOpcode, "NOP", "NOOP", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1252 | Case &H7 : Return DecodeOperands(oOpcode, "RESTART", "RESTART", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_RETURN) 1253 | Case &H8 : Return DecodeOperands(oOpcode, "RET_POPPED", "RSTACK", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_RETURN) 1254 | Case &HA : Return DecodeOperands(oOpcode, "QUIT", "QUIT", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_RETURN) 1255 | Case &HB : Return DecodeOperands(oOpcode, "NEW_LINE", "CRLF", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1256 | Case &HD : Return DecodeOperands(oOpcode, "VERIFY", "VERIFY", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1257 | Case Else 1258 | Select Case ZVersion 1259 | Case 1, 2, 3 1260 | Select Case iCode 1261 | Case &H5 : Return DecodeOperands(oOpcode, "SAVE", "SAVE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1262 | Case &H6 : Return DecodeOperands(oOpcode, "RESTORE", "RESTORE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1263 | Case &H9 : Return DecodeOperands(oOpcode, "POP", "FSTACK", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1264 | Case &HC : Return DecodeOperands(oOpcode, "SHOW_STATUS", "USL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1265 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1266 | End Select 1267 | Case 4 1268 | Select Case iCode 1269 | Case &H5 : Return DecodeOperands(oOpcode, "SAVE", "SAVE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1270 | Case &H6 : Return DecodeOperands(oOpcode, "RESTORE", "RESTORE", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1271 | Case &H9 : Return DecodeOperands(oOpcode, "POP", "FSTACK", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1272 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1273 | End Select 1274 | Case 5, 7, 8 1275 | Select Case iCode 1276 | Case &H9 : Return DecodeOperands(oOpcode, "CATCH", "CATCH", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1277 | 'From a bug in Wishbringer V23 1278 | Case &HC : Return DecodeOperands(oOpcode, "SHOW_STATUS", "USL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_PLAIN) 1279 | Case Else : Return DecodeOperands(oOpcode, "ILLEGAL", "ILLEGAL", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_NONE, EnumType.T_ILLEGAL) 1280 | End Select 1281 | Case 6 1282 | Select Case iCode 1283 | Case &H9 : Return DecodeOperands(oOpcode, "CATCH", "CATCH", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_STORE, EnumType.T_PLAIN) 1284 | Case &HF : Return DecodeOperands(oOpcode, "PIRACY", "ORIGINAL?", EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumOperand.P_NIL, EnumExtra.E_BRANCH, EnumType.T_PLAIN) 1285 | End Select 1286 | End Select 1287 | End Select 1288 | End Select 1289 | 1290 | Dim oReturn As New DecodeResult With {.status = EnumStatus.BAD_OPCODE} 1291 | Return oReturn 1292 | Catch 1293 | Return New DecodeResult With {.status = EnumStatus.BAD_ENTRY} 1294 | End Try 1295 | End Function 1296 | 1297 | Private Function DecodeOperands(pOpcode As Opcode, psOpcodeNameInf As String, psOpcodeNameZil As String, pPar1 As EnumOperand, pPar2 As EnumOperand, pPar3 As EnumOperand, pPar4 As EnumOperand, pExtra As EnumExtra, pType As EnumType) As DecodeResult 1298 | pOpcode.OperandType(0) = pPar1 1299 | pOpcode.OperandType(1) = pPar2 1300 | pOpcode.OperandType(2) = pPar3 1301 | pOpcode.OperandType(3) = pPar4 1302 | pOpcode.Extra = pExtra 1303 | pOpcode.Type = pType 1304 | pOpcode.OpcodeText = "@" & psOpcodeNameInf.ToLower & " / " & psOpcodeNameZil 1305 | For i = 0 To 20 1306 | If pOpcode.Address + i < byteGame.Length Then 1307 | pOpcode.OpcodeBytes(i) = byteGame(pOpcode.Address + i) 1308 | End If 1309 | Next 1310 | 1311 | ' zork0-beta-r242-s880830.z6 and zork0-r242-s880901.z6 contains code that uses 3 parameters for WINGET. 1312 | ' Source code: 1313 | ' 1314 | ' > 1315 | ' 1317 | ' > 1318 | ' 1319 | ' Compiles to 02 BE 13 8B 01 70 8B 02 CF 1F 70 8B 01 00 B8 00 at address 0x1cc28. 1320 | ' 1321 | ' This is outside the standards of the z-machine and probably only was legel during development 1322 | ' of z6 in an unreleased compiler. 1323 | ' For completeness unz can disassemble it even though probably no interpreter can run it. 1324 | If pOpcode.OpcodeClass = EnumOpcodeClass.EXTENDED_OPERAND And pOpcode.Code = &H13 And pOpcode.ExtModeByte = &H8B Then 1325 | pOpcode.OperandType(0) = EnumOperand.P_NUMBER 1326 | pOpcode.OperandType(1) = EnumOperand.P_LOW_ADDR 1327 | pOpcode.OperandType(2) = EnumOperand.P_NUMBER 1328 | pOpcode.Extra = EnumExtra.E_NONE 1329 | pOpcode.Text = "*** ILLEGAL SET OF PARAMETERS FOR THIS OPCODE, ONLY USED IN ZORK0 DURING DEVELOPMENT ***" 1330 | End If 1331 | 1332 | If pType = EnumType.T_ILLEGAL Then 1333 | Dim oReturn As New DecodeResult With {.status = EnumStatus.BAD_OPCODE} 1334 | Return oReturn 1335 | End If 1336 | 1337 | Dim typeQuitRestart As Boolean = False 1338 | If pOpcode.Code = &HBA Or pOpcode.Code = &HB7 Then 1339 | ' QUIT or RESTART (should this be expanded to other RETURN_types?) 1340 | ' These are considered as RETURN-type if the next opcode is illegal, otherwise they are PLAIN. 1341 | ' If the next address is a valid routine startIndex, it is also considered as RETURN. 1342 | typeQuitRestart = True 1343 | If Not (byteGame(pOpcode.Address + 1) < 16 And Helper.GetNextValidPackedAddress(byteGame, pOpcode.Address + 1) = pOpcode.Address + 1) Then 1344 | Dim bOldSilent As Boolean = bSilent 1345 | bSilent = True 1346 | If DecodeCode(pOpcode.Address + 1).status = EnumStatus.BAD_OPCODE Then 1347 | pOpcode.Type = EnumType.T_RETURN 1348 | Else 1349 | pOpcode.Type = EnumType.T_PLAIN 1350 | End If 1351 | bSilent = bOldSilent 1352 | 1353 | End If 1354 | End If 1355 | Dim iOffset As Integer = DumpOpcode(pOpcode) 1356 | Dim sText As String = psOpcodeNameInf 1357 | If syntax = 1 Then sText = sText.ToLower 1358 | If syntax = 2 Then sText = psOpcodeNameZil 1359 | sText &= pOpcode.OperandText 1360 | If pOpcode.Text.Trim <> "" Then 1361 | sText = sText & " " & Convert.ToChar(34) & pOpcode.Text & Convert.ToChar(34) 1362 | End If 1363 | If Not bSilent Then 1364 | If syntax = 3 Then Console.WriteLine(pOpcode.PseudoCode) Else Console.WriteLine(sText) 1365 | If bShowZCodeVerbose Then pOpcode.PrintVerbose() 1366 | End If 1367 | 1368 | Dim oRet As New DecodeResult With {.status = EnumStatus.END_OF_INSTRUCTION} 1369 | If pOpcode.Type = EnumType.T_ILLEGAL Then oRet.status = EnumStatus.BAD_OPCODE 1370 | oRet.nextPC = pOpcode.Address + iOffset 1371 | If (pOpcode.Type = EnumType.T_RETURN Or typeQuitRestart) And oRet.nextPC > high_pc Then oRet.status = EnumStatus.END_OF_ROUTINE 1372 | 1373 | Return oRet 1374 | End Function 1375 | 1376 | Private Function DumpOpcode(pOpcode As Opcode) As Integer 1377 | Dim count As Integer = 0 1378 | Dim iParameterCount As Integer = 0 1379 | Dim bBranchLong As Boolean = False 1380 | 1381 | If Not bSilent Then Console.Write("{0:X5} ", pOpcode.Address) 1382 | 1383 | If pOpcode.OpcodeClass = EnumOpcodeClass.EXTENDED_OPERAND Then 1384 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address)) 1385 | count += 1 1386 | End If 1387 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1388 | count += 1 1389 | 1390 | If pOpcode.OpcodeClass = EnumOpcodeClass.ONE_OPERAND Then 1391 | ' Bit 5, 4 determine operand type 1392 | ' 00 = long immediate (2 bytes) 1393 | ' 01 = immediate (1 byte 00xx) 1394 | ' 10 = variable (1 byte) 1395 | ' 11 = undefined 1396 | iParameterCount = 1 1397 | pOpcode.OperandLen(0) = 1 1398 | If (pOpcode.Code And &H30) = 0 Then 1399 | pOpcode.OperandLen(0) = 2 1400 | pOpcode.OperandAddrMode(0) = EnumAddressMode.LONG_IMMEDIATE 1401 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1402 | pOpcode.OperandVal(0) = byteGame(pOpcode.Address + count) 1403 | count += 1 1404 | End If 1405 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1406 | pOpcode.OperandVal(0) = pOpcode.OperandVal(0) * 256 + byteGame(pOpcode.Address + count) 1407 | If (pOpcode.Code And &H30) = &H10 Then pOpcode.OperandAddrMode(0) = EnumAddressMode.IMMEDIATE 1408 | If (pOpcode.Code And &H30) = &H20 Then pOpcode.OperandAddrMode(0) = EnumAddressMode.VARIABLE 1409 | count += 1 1410 | 1411 | If pOpcode.OperandType(0) = EnumOperand.P_LABEL Then 1412 | ' JUMP 1413 | Dim offset As Integer = Helper.GetAdressFromWord(byteGame, pOpcode.Address + count - 2) 1414 | If offset > 32767 Then offset = (offset And 32767) * -1 1415 | If offset > 0 Then 1416 | If (pOpcode.Address + count + offset - 2) > high_pc Then 1417 | high_pc = pOpcode.Address + count + offset - 2 1418 | End If 1419 | End If 1420 | End If 1421 | End If 1422 | 1423 | If pOpcode.OpcodeClass = EnumOpcodeClass.TWO_OPERAND Then 1424 | ' Bit 6, 5 determine operand type 1425 | ' 00 = immediate, immediate (2 bytes) 1426 | ' 01 = immediate, variable (2 bytes) 1427 | ' 10 = variable, immediate (2 bytes) 1428 | ' 11 = variable, variable (2 bytes) 1429 | iParameterCount = 2 1430 | pOpcode.OperandLen(0) = 1 1431 | pOpcode.OperandLen(1) = 1 1432 | pOpcode.OperandVal(0) = byteGame(pOpcode.Address + count) 1433 | pOpcode.OperandVal(1) = byteGame(pOpcode.Address + count + 1) 1434 | If (pOpcode.Code And &H60) = &H0 Then 1435 | pOpcode.OperandAddrMode(0) = EnumAddressMode.IMMEDIATE 1436 | pOpcode.OperandAddrMode(1) = EnumAddressMode.IMMEDIATE 1437 | End If 1438 | If (pOpcode.Code And &H60) = &H20 Then 1439 | pOpcode.OperandAddrMode(0) = EnumAddressMode.IMMEDIATE 1440 | pOpcode.OperandAddrMode(1) = EnumAddressMode.VARIABLE 1441 | End If 1442 | If (pOpcode.Code And &H60) = &H40 Then 1443 | pOpcode.OperandAddrMode(0) = EnumAddressMode.VARIABLE 1444 | pOpcode.OperandAddrMode(1) = EnumAddressMode.IMMEDIATE 1445 | End If 1446 | If (pOpcode.Code And &H60) = &H60 Then 1447 | pOpcode.OperandAddrMode(0) = EnumAddressMode.VARIABLE 1448 | pOpcode.OperandAddrMode(1) = EnumAddressMode.VARIABLE 1449 | End If 1450 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1451 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count + 1)) 1452 | count += 2 1453 | End If 1454 | 1455 | If pOpcode.OpcodeClass = EnumOpcodeClass.VARIABLE_OPERAND Or pOpcode.OpcodeClass = EnumOpcodeClass.EXTENDED_OPERAND Then 1456 | ' Each pair of bits in next 1 or 2 bytes (XCALL & IXCALL) determine operand type 1457 | ' 00 = long immediate (2 bytes) 1458 | ' 01 = immediate (1 byte 00xx) 1459 | ' 10 = variable (1 byte) 1460 | ' 11 = no more operands 1461 | Dim iOperandBytes As Integer = 0 1462 | If (pOpcode.Code And &H3F) = &H2C Or (pOpcode.Code And &H3F) = &H3A Then 1463 | ' CALL_VS2 & CALL_VN2, next two bytes specify length of data bytes 1464 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1465 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count + 1)) 1466 | Dim iWord As Integer = Helper.GetAdressFromWord(byteGame, pOpcode.Address + count) 1467 | For shift As Integer = 14 To 0 Step -2 1468 | Dim iBits As Integer = ((iWord >> shift) And 3) 1469 | If iBits = 3 Then Exit For 1470 | iParameterCount += 1 1471 | If iBits = 0 Then 1472 | pOpcode.OperandLen(iParameterCount - 1) = 2 1473 | pOpcode.OperandVal(iParameterCount - 1) = byteGame(pOpcode.Address + count + iOperandBytes + 2) * 256 + byteGame(pOpcode.Address + +count + iOperandBytes + 3) 1474 | pOpcode.OperandAddrMode(iParameterCount - 1) = EnumAddressMode.LONG_IMMEDIATE 1475 | iOperandBytes += 2 1476 | ElseIf iBits = 1 Or iBits = 2 Then 1477 | pOpcode.OperandLen(iParameterCount - 1) = 1 1478 | pOpcode.OperandVal(iParameterCount - 1) = byteGame(pOpcode.Address + count + iOperandBytes + 2) 1479 | If iBits = 1 Then 1480 | pOpcode.OperandAddrMode(iParameterCount - 1) = EnumAddressMode.IMMEDIATE 1481 | Else 1482 | pOpcode.OperandAddrMode(iParameterCount - 1) = EnumAddressMode.VARIABLE 1483 | End If 1484 | iOperandBytes += 1 1485 | End If 1486 | Next 1487 | count += 2 1488 | Else 1489 | ' Next byte specify length of data bytes 1490 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1491 | Dim iByte As Integer = byteGame(pOpcode.Address + count) 1492 | For shift As Integer = 6 To 0 Step -2 1493 | Dim iBits As Integer = ((iByte >> shift) And 3) 1494 | If iBits = 3 Then Exit For 1495 | iParameterCount += 1 1496 | If iBits = 0 Then 1497 | pOpcode.OperandLen(iParameterCount - 1) = 2 1498 | pOpcode.OperandVal(iParameterCount - 1) = byteGame(pOpcode.Address + count + iOperandBytes + 1) * 256 + byteGame(pOpcode.Address + +count + iOperandBytes + 2) 1499 | pOpcode.OperandAddrMode(iParameterCount - 1) = EnumAddressMode.LONG_IMMEDIATE 1500 | iOperandBytes += 2 1501 | ElseIf iBits = 1 Or iBits = 2 Then 1502 | pOpcode.OperandLen(iParameterCount - 1) = 1 1503 | pOpcode.OperandVal(iParameterCount - 1) = byteGame(pOpcode.Address + count + iOperandBytes + 1) 1504 | If iBits = 1 Then 1505 | pOpcode.OperandAddrMode(iParameterCount - 1) = EnumAddressMode.IMMEDIATE 1506 | Else 1507 | pOpcode.OperandAddrMode(iParameterCount - 1) = EnumAddressMode.VARIABLE 1508 | End If 1509 | iOperandBytes += 1 1510 | End If 1511 | Next 1512 | count += 1 1513 | End If 1514 | For i As Integer = 0 To iOperandBytes - 1 1515 | PrintLF(count + i) 1516 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count + i)) 1517 | Next 1518 | count += iOperandBytes 1519 | End If 1520 | 1521 | ' Decode Extra 1522 | If pOpcode.Extra = EnumExtra.E_STORE Or pOpcode.Extra = EnumExtra.E_BOTH Then 1523 | ' One byte for variable to store result in 1524 | pOpcode.StoreVal = byteGame(pOpcode.Address + count) 1525 | PrintLF(count) 1526 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1527 | count += 1 1528 | End If 1529 | If pOpcode.Extra = EnumExtra.E_BRANCH Or pOpcode.Extra = EnumExtra.E_BOTH Then 1530 | ' 1 or 2 bytes for address for branch. 1531 | ' Bit 7 determine if branch on true or false 1532 | ' 0 = Branch when false 1533 | ' 1 = branch when true 1534 | ' Bit 6 determine branch type 1535 | ' 0 = long address (2 bytes, 14 bits for long offset) 1536 | ' 1 = short address (1 byte, 6 bits for offset) 1537 | PrintLF(count) 1538 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1539 | pOpcode.BranchTest = True 1540 | If (byteGame(pOpcode.Address + count) And &H80) = 0 Then pOpcode.BranchTest = False 1541 | Dim offset As Integer = 0 1542 | If (byteGame(pOpcode.Address + count) And 64) = 0 Then 1543 | bBranchLong = True 1544 | PrintLF(count + 1) 1545 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count + 1)) 1546 | offset = (byteGame(pOpcode.Address + count) And &H3F) * 256 + byteGame(pOpcode.Address + count + 1) 1547 | count += 2 1548 | Else 1549 | offset = (byteGame(pOpcode.Address + count) And &H3F) 1550 | count += 1 1551 | End If 1552 | If offset > &H1FFF Then offset = ((offset And &H1FFF) Or (Not &H1FFF)) 1553 | pOpcode.BranchAddr = pOpcode.Address + count + offset - 2 1554 | If pOpcode.BranchAddr < startAddress Then pOpcode.Type = EnumType.T_ILLEGAL 1555 | If offset > 1 Then 1556 | If pOpcode.BranchAddr > high_pc Then high_pc = pOpcode.BranchAddr 1557 | End If 1558 | ' offset = 0: RFALSE 1559 | ' offset = 1: RTRUE 1560 | If offset = 0 Or offset = 1 Then pOpcode.BranchAddr = offset 1561 | End If 1562 | 1563 | If pOpcode.Extra = EnumExtra.E_TEXT Then 1564 | ' z-string. Terminated when bit 15 of word is set. 1565 | Dim textStart As Integer = pOpcode.Address + count 1566 | pOpcode.Text = Helper.ExtractZString(byteGame, textStart, sAbbreviations, alphabet, showAbbrevsInsertion) 1567 | Do 1568 | PrintLF(count) 1569 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count)) 1570 | PrintLF(count + 1) 1571 | If Not bSilent Then Console.Write("{0:X2} ", byteGame(pOpcode.Address + count + 1)) 1572 | count += 2 1573 | Loop Until (byteGame(pOpcode.Address + count - 2) And 128) = 128 1574 | If bSilent And ((pOpcode.Code And &HB2) = &HB2 Or (pOpcode.Code And &HB3) = &HB3) Then ' PRINTI (PRINT) or PRINTR (PRINT_RET) 1575 | inlineStrings.Add(New InlineString With {.text = Helper.ExtractZString(byteGame, textStart, sAbbreviations, alphabet, False), 1576 | .size = pOpcode.Address + count - textStart}) 1577 | End If 1578 | End If 1579 | 1580 | If (count Mod 8) = 0 Then 1581 | If Not bSilent Then Console.Write(" ") 1582 | Else 1583 | If Not bSilent Then Console.Write(" ".Substring(0, (8 - (count Mod 8)) * 3 + 1)) 1584 | End If 1585 | 1586 | ' Find call to routine with highest address. 1587 | ' Only counts long_immediate and therefore excludes TWO_OPERAND calls 1588 | If pOpcode.Type = EnumType.T_CALL And pOpcode.OperandType(0) = EnumOperand.P_ROUTINE Then 1589 | Dim routine_address As Integer = 0 1590 | If pOpcode.OpcodeClass = EnumOpcodeClass.ONE_OPERAND Then 1591 | If (pOpcode.Code And &H30) = 0 Then 1592 | routine_address = Helper.GetAdressFromPacked(byteGame, pOpcode.Address + 1, True) 1593 | End If 1594 | ElseIf Not pOpcode.OpcodeClass = EnumOpcodeClass.TWO_OPERAND Then 1595 | Dim bits As Integer = byteGame(pOpcode.Address + 1) And 192 1596 | ' 00 = long immediate (2 bytes) 1597 | ' 01 = immediate (1 byte 00xx) 1598 | ' 10 = variable (1 byte) 1599 | ' 11 = no more operands 1600 | If bits = 0 Then 1601 | If (pOpcode.Code And &H3F) = &H2C Or (pOpcode.Code And &H3F) = &H3A Then 1602 | routine_address = Helper.GetAdressFromPacked(byteGame, pOpcode.Address + 3, True) 1603 | Else 1604 | routine_address = Helper.GetAdressFromPacked(byteGame, pOpcode.Address + 2, True) 1605 | End If 1606 | End If 1607 | End If 1608 | If routine_address > highest_routine Then highest_routine = routine_address 1609 | If routine_address > 0 And routine_address < lowest_routine Then lowest_routine = routine_address 1610 | callsTo.Add(New CallsFromTo With {.fromAddress = startAddress, .toAddress = routine_address}) 1611 | End If 1612 | 1613 | ' Find call to packed string with lowest address 1614 | If pOpcode.OpcodeClass = EnumOpcodeClass.ONE_OPERAND AndAlso pOpcode.Code = &H8D Then 1615 | ' 8D = print_paddr with long immediate 1616 | Dim string_address As Integer = Helper.GetAdressFromPacked(byteGame, pOpcode.Address + 1, False) 1617 | If string_address < lowest_string Then lowest_string = string_address 1618 | End If 1619 | 1620 | ' Format operands/parameter text 1621 | For i As Integer = 0 To iParameterCount - 1 1622 | Dim operandType As EnumOperand = pOpcode.OperandType(i) 1623 | Dim operandVal As Integer = pOpcode.OperandVal(i) 1624 | If i > 3 Then 1625 | operandType = EnumOperand.P_ANYTHING 1626 | pOpcode.OperandType(i) = EnumOperand.P_ANYTHING 1627 | End If 1628 | If pOpcode.OperandAddrMode(i) = EnumAddressMode.VARIABLE Then operandType = EnumOperand.P_VAR 1629 | If iParameterCount > 1 And pOpcode.Type = EnumType.T_CALL And syntax < 2 And i = 1 Then pOpcode.OperandText &= " (" 1630 | 1631 | ' Comment from txd 1632 | ' To make the code more readable, VAR type operands are Not translated 1633 | ' as constants, eg. INC 5 Is actually printed as INC L05. However, if 1634 | ' the VAR type operand _is_ a variable, the translation should look Like 1635 | ' INC [L05], ie. increment the variable which Is given by the contents 1636 | ' of local variable #5. Earlier versions of "txd" translated both cases 1637 | ' as INC L05. This bug was finally detected by Graham Nelson. 1638 | If pOpcode.OperandType(i) = EnumOperand.P_VAR And pOpcode.OperandAddrMode(i) = EnumAddressMode.VARIABLE Then 1639 | operandType = EnumOperand.P_INDIRECT 1640 | pOpcode.OperandType(i) = operandType 1641 | End If 1642 | 1643 | Select Case operandType 1644 | Case EnumOperand.P_ANYTHING 1645 | Dim oStringData As StringData = validStringList.Find(Function(x) x.entryPointPacked = operandVal) 1646 | Dim dictEntry As DictionaryEntry = DictEntriesList.GetEntryAtAddress(operandVal) 1647 | If oStringData IsNot Nothing Then 1648 | If syntax = 1 Then 1649 | pOpcode.OperandText = pOpcode.OperandText & " s" & oStringData.number.ToString("D4") 1650 | Else 1651 | pOpcode.OperandText = pOpcode.OperandText & " S" & oStringData.number.ToString("D4") 1652 | End If 1653 | pOpcode.OperandStringPseudo(i) = "s" & oStringData.number.ToString("D4") 1654 | End If 1655 | If oStringData IsNot Nothing And dictEntry IsNot Nothing Then 1656 | If syntax = 1 Then 1657 | pOpcode.OperandText &= " or" 1658 | Else 1659 | pOpcode.OperandText &= " OR" 1660 | End If 1661 | pOpcode.OperandStringPseudo(i) &= "/" 1662 | End If 1663 | If dictEntry IsNot Nothing Then 1664 | If syntax = 2 Then 1665 | pOpcode.OperandText = pOpcode.OperandText & " W?" & dictEntry.dictWord.ToUpper 1666 | Else 1667 | pOpcode.OperandText = pOpcode.OperandText & " " & Convert.ToChar(34) & dictEntry.dictWord & Convert.ToChar(34) 1668 | End If 1669 | pOpcode.OperandStringPseudo(i) &= Convert.ToChar(34) & dictEntry.dictWord & Convert.ToChar(34) 1670 | End If 1671 | If oStringData Is Nothing And dictEntry Is Nothing Then 1672 | pOpcode.OperandText = pOpcode.OperandText & " " & TextNumber(operandVal, pOpcode.OperandLen(i), syntax, True) 1673 | pOpcode.OperandStringPseudo(i) = TextNumber(operandVal, pOpcode.OperandLen(i), 1, True) 1674 | End If 1675 | Case EnumOperand.P_ATTRNUM 1676 | If syntax = 0 Then pOpcode.OperandText = pOpcode.OperandText & " ATTRIBUTE" & operandVal.ToString 1677 | If syntax = 1 Then pOpcode.OperandText = pOpcode.OperandText & " attribute" & operandVal.ToString 1678 | If syntax = 2 Then pOpcode.OperandText = pOpcode.OperandText & " ATTRIBUTE" & operandVal.ToString 1679 | pOpcode.OperandStringPseudo(i) = "attribute" & operandVal.ToString 1680 | Case EnumOperand.P_INDIRECT 1681 | pOpcode.OperandText = pOpcode.OperandText & " [" & TextVariable(operandVal, syntax) & "]" 1682 | pOpcode.OperandStringPseudo(i) = " [" & TextVariable(operandVal, 3) & "]" 1683 | Case EnumOperand.P_LABEL 1684 | Dim Address As Integer = pOpcode.Address + 1 1685 | If operandVal > 32767 Then 1686 | Address -= (65536 - operandVal) 1687 | Else 1688 | Address += operandVal 1689 | End If 1690 | If syntax = 0 Then pOpcode.OperandText = pOpcode.OperandText & " 0x" & Address.ToString("X4") 1691 | If syntax = 1 Then pOpcode.OperandText = pOpcode.OperandText & " 0x" & Address.ToString("x4") 1692 | If syntax = 2 Then pOpcode.OperandText = pOpcode.OperandText & " 0x" & Address.ToString("X4") 1693 | pOpcode.OperandStringPseudo(i) = "0x" & Address.ToString("x4") 1694 | Case EnumOperand.P_LOW_ADDR 1695 | Dim dictEntry As DictionaryEntry = DictEntriesList.GetEntryAtAddress(operandVal) 1696 | If dictEntry IsNot Nothing Then 1697 | pOpcode.OperandText = pOpcode.OperandText & " " & Convert.ToChar(34) & dictEntry.dictWord & Convert.ToChar(34) 1698 | pOpcode.OperandStringPseudo(i) = Convert.ToChar(34) & dictEntry.dictWord & Convert.ToChar(34) 1699 | Else 1700 | pOpcode.OperandText = pOpcode.OperandText & " " & TextNumber(operandVal, pOpcode.OperandLen(i), syntax, False) 1701 | pOpcode.OperandStringPseudo(i) = TextNumber(operandVal, pOpcode.OperandLen(i), 1, False) 1702 | If bSilent Then 1703 | ' Collect all possible startpoints for an array 1704 | If operandVal > 0 Then 1705 | If (pOpcode.OpcodeClass = EnumOpcodeClass.TWO_OPERAND And (pOpcode.Code And &H1F) = &HF) Or ' LOADB 1706 | (pOpcode.OpcodeClass = EnumOpcodeClass.TWO_OPERAND And (pOpcode.Code And &H1F) = &H10) Or ' LOADW 1707 | (pOpcode.OpcodeClass = EnumOpcodeClass.VARIABLE_OPERAND And (pOpcode.Code And &H3F) = &H21) Or ' STOREB 1708 | (pOpcode.OpcodeClass = EnumOpcodeClass.VARIABLE_OPERAND And (pOpcode.Code And &H3F) = &H22) Then ' STOREW 1709 | arraysStart.Add(operandVal) 1710 | End If 1711 | End If 1712 | End If 1713 | End If 1714 | Case EnumOperand.P_NIL 1715 | pOpcode.OperandText &= " Illegal_parameter" 1716 | pOpcode.OperandStringPseudo(i) = "Illegal_parameter" 1717 | Case EnumOperand.P_NUMBER 1718 | If syntax = 2 And (pOpcode.Code And &H3F) = &H3F Then ' ASSIGNED?, the number points to a local variable 1719 | pOpcode.OperandText = pOpcode.OperandText & " '" & TextVariable(operandVal, syntax) 1720 | Else 1721 | pOpcode.OperandText = pOpcode.OperandText & " " & TextNumber(operandVal, pOpcode.OperandLen(i), syntax, True) 1722 | End If 1723 | pOpcode.OperandStringPseudo(i) = TextNumber(operandVal, pOpcode.OperandLen(i), 2, True) 1724 | Case EnumOperand.P_OBJECT 1725 | If syntax = 0 Then pOpcode.OperandText = pOpcode.OperandText & " OBJECT" & operandVal.ToString 1726 | If syntax = 1 Then pOpcode.OperandText = pOpcode.OperandText & " object" & operandVal.ToString 1727 | If syntax = 2 Then pOpcode.OperandText = pOpcode.OperandText & " OBJECT" & operandVal.ToString 1728 | pOpcode.OperandStringPseudo(i) = "object" & operandVal.ToString 1729 | Case EnumOperand.P_PATTR 1730 | Dim sDirOut As String = "" 1731 | Select Case operandVal 1732 | Case 1 : sDirOut = "OUTPUT_ENABLE" 1733 | Case 2 : sDirOut = "SCRIPTING_ENABLE" 1734 | Case 3 : sDirOut = "REDIRECT_ENABLE" 1735 | Case 4 : sDirOut = "RECORD_ENABLE" 1736 | Case -1 : sDirOut = "OUTPUT_DISABLE" 1737 | Case -2 : sDirOut = "SCRIPTING_DISABLE" 1738 | Case -3 : sDirOut = "REDIRECT_DISABLE" 1739 | Case -4 : sDirOut = "RECORD_DISABLE" 1740 | Case Else : sDirOut = TextNumber(operandVal, pOpcode.OperandLen(i), syntax, False) 1741 | End Select 1742 | If syntax = 1 Then sDirOut = sDirOut.ToLower 1743 | pOpcode.OperandText = pOpcode.OperandText & " " & sDirOut 1744 | pOpcode.OperandStringPseudo(i) = sDirOut.ToLower 1745 | Case EnumOperand.P_PCHAR 1746 | Dim character As Char = CChar(Char.ConvertFromUtf32(operandVal)) 1747 | If Not Char.IsControl(character) Then 1748 | pOpcode.OperandText = pOpcode.OperandText & " '" & character & "'" 1749 | pOpcode.OperandStringPseudo(i) = "'" & character & "'" 1750 | Else 1751 | pOpcode.OperandText = pOpcode.OperandText & " " & TextNumber(operandVal, pOpcode.OperandLen(i), syntax, False) 1752 | pOpcode.OperandStringPseudo(i) = TextNumber(operandVal, pOpcode.OperandLen(i), 1, False) 1753 | End If 1754 | Case EnumOperand.P_PROPNUM 1755 | If operandVal < propertyMin Or operandVal > propertyMax Then 1756 | pOpcode.OperandText = pOpcode.OperandText & " " & "[Invalid property: 0x" & operandVal.ToString("X2") & "]" 1757 | pOpcode.OperandStringPseudo(i) = "[Invalid property: 0x" & operandVal.ToString("X2") & "]" 1758 | Else 1759 | If syntax = 0 Then pOpcode.OperandText = pOpcode.OperandText & " PROPERTY" & operandVal.ToString 1760 | If syntax = 1 Then pOpcode.OperandText = pOpcode.OperandText & " property" & operandVal.ToString 1761 | If syntax = 2 Then pOpcode.OperandText = pOpcode.OperandText & " P?" & operandVal.ToString 1762 | pOpcode.OperandStringPseudo(i) = "property" & operandVal.ToString 1763 | End If 1764 | Case EnumOperand.P_ROUTINE 1765 | If operandVal <> 0 Then 1766 | Dim oRoutineData As RoutineData = validRoutineList.Find(Function(x) x.entryPointPacked = operandVal) 1767 | If oRoutineData IsNot Nothing Then 1768 | If syntax = 0 Then pOpcode.OperandText = pOpcode.OperandText & " 0x" & oRoutineData.entryPoint.ToString("X4") 1769 | If syntax = 1 Then pOpcode.OperandText = pOpcode.OperandText & " 0x" & oRoutineData.entryPoint.ToString("x4") 1770 | If syntax = 2 Then pOpcode.OperandText = pOpcode.OperandText & " 0x" & oRoutineData.entryPoint.ToString("X4") 1771 | pOpcode.OperandStringPseudo(i) = "0x" & oRoutineData.entryPoint.ToString("x4") 1772 | Else 1773 | pOpcode.OperandText = pOpcode.OperandText & " " & "[Invalid routine: 0x" & Helper.UnpackAddress(operandVal, byteGame, True).ToString("X4") & "]" 1774 | pOpcode.OperandStringPseudo(i) = "[Invalid routine: 0x" & Helper.UnpackAddress(operandVal, byteGame, True).ToString("X4") & "]" 1775 | End If 1776 | Else 1777 | pOpcode.OperandText &= " 0" 1778 | pOpcode.OperandStringPseudo(i) = "0" 1779 | End If 1780 | Case EnumOperand.P_STATIC 1781 | Dim oStringData As StringData = validStringList.Find(Function(x) x.entryPointPacked = operandVal) 1782 | If oStringData IsNot Nothing Then 1783 | If syntax = 1 Then 1784 | pOpcode.OperandText = pOpcode.OperandText & " s" & oStringData.number.ToString("D4") & " " & Convert.ToChar(34) & oStringData.GetText(showAbbrevsInsertion) & Convert.ToChar(34) 1785 | Else 1786 | pOpcode.OperandText = pOpcode.OperandText & " S" & oStringData.number.ToString("D4") & " " & Convert.ToChar(34) & oStringData.GetText(showAbbrevsInsertion) & Convert.ToChar(34) 1787 | End If 1788 | pOpcode.OperandStringPseudo(i) = "s" & oStringData.number.ToString("D4") & " " & Convert.ToChar(34) & oStringData.GetText(showAbbrevsInsertion) & Convert.ToChar(34) 1789 | Else 1790 | pOpcode.OperandText = pOpcode.OperandText & " " & "[Invalid string: " & Helper.UnpackAddress(operandVal, byteGame, False).ToString("X5") & "]" 1791 | pOpcode.OperandStringPseudo(i) = "[Invalid string: " & Helper.UnpackAddress(operandVal, byteGame, False).ToString("X5") & "]" 1792 | End If 1793 | Case EnumOperand.P_VAR 1794 | If syntax < 2 Then 1795 | pOpcode.OperandText = pOpcode.OperandText & " " & TextVariable(operandVal, syntax) 1796 | Else 1797 | If pOpcode.OperandType(i) = EnumOperand.P_VAR Then ' Original type was P_VAR 1798 | If (pOpcode.Code And &HF) = &HE And operandVal = 0 Then ' VALUE and STACK 1799 | pOpcode.OperandText = pOpcode.OperandText & " " & TextVariable(operandVal, syntax) 1800 | Else 1801 | pOpcode.OperandText = pOpcode.OperandText & " '" & TextVariable(operandVal, syntax) 1802 | End If 1803 | Else 1804 | pOpcode.OperandText = pOpcode.OperandText & " " & TextVariable(operandVal, syntax) 1805 | End If 1806 | End If 1807 | pOpcode.OperandStringPseudo(i) = TextVariable(operandVal, 3) 1808 | Case EnumOperand.P_VATTR 1809 | Dim sFontStyle As String = "" 1810 | Select Case operandVal 1811 | Case 0 : sFontStyle = "ROMAN" 1812 | Case 1 : sFontStyle = "REVERSE" 1813 | Case 2 : sFontStyle = "BOLDFACE" 1814 | Case 4 : sFontStyle = "EMPHASIS" 1815 | Case 8 : sFontStyle = "FIXED_FONT" 1816 | Case Else : sFontStyle = TextNumber(operandVal, pOpcode.OperandLen(i), syntax, False) 1817 | End Select 1818 | If syntax = 1 Then sFontStyle = sFontStyle.ToLower 1819 | pOpcode.OperandText = pOpcode.OperandText & " " & sFontStyle 1820 | pOpcode.OperandStringPseudo(i) = sFontStyle.ToLower 1821 | End Select 1822 | If syntax < 2 And iParameterCount > 1 And pOpcode.Type = EnumType.T_CALL And i < iParameterCount - 1 And i > 0 Then pOpcode.OperandText &= "," 1823 | If syntax = 2 And iParameterCount > 0 And i < iParameterCount - 1 Then pOpcode.OperandText &= "," 1824 | Next 1825 | If iParameterCount > 1 And pOpcode.Type = EnumType.T_CALL And syntax < 2 Then 1826 | pOpcode.OperandText = (pOpcode.OperandText & ")").Replace("( ", "(").Replace(", ", ",") 1827 | End If 1828 | If syntax = 2 Then pOpcode.OperandText = pOpcode.OperandText.Replace(", ", ",") 1829 | If pOpcode.Extra = EnumExtra.E_BOTH Or pOpcode.Extra = EnumExtra.E_STORE Then 1830 | Dim sStoreText As String 1831 | sStoreText = TextVariable(pOpcode.StoreVal, syntax) 1832 | If pOpcode.StoreVal = 0 And syntax = 0 Then sStoreText = "-(SP)" 1833 | pOpcode.StoreStringPseudo = TextVariable(pOpcode.StoreVal, 3) 1834 | 1835 | ' Collect statistics on globals 1836 | Dim value As Integer = pOpcode.StoreVal - 16 1837 | If value > highest_global Then highest_global = value 1838 | If value > -1 Then usedGlobals.Add(value) 1839 | 1840 | If syntax < 2 Then pOpcode.OperandText = pOpcode.OperandText & " -> " & sStoreText Else pOpcode.OperandText = pOpcode.OperandText & " >" & sStoreText 1841 | End If 1842 | If pOpcode.Extra = EnumExtra.E_BOTH Or pOpcode.Extra = EnumExtra.E_BRANCH Then 1843 | Dim sBranchText As String = "" 1844 | If pOpcode.BranchTest Then 1845 | If syntax = 0 Then sBranchText = "[TRUE] " 1846 | If syntax = 2 Then sBranchText = "/" 1847 | Else 1848 | If syntax = 0 Then sBranchText = "[FALSE] " 1849 | If syntax = 1 Then sBranchText = "~" 1850 | If syntax = 2 Then sBranchText = "\" 1851 | End If 1852 | If pOpcode.BranchAddr = 0 Then 1853 | If syntax = 2 Then sBranchText &= "FALSE" Else sBranchText &= "RFALSE" 1854 | ElseIf pOpcode.BranchAddr = 1 Then 1855 | If syntax = 2 Then sBranchText &= "TRUE" Else sBranchText &= "RTRUE" 1856 | Else 1857 | sBranchText = sBranchText & "0x" & pOpcode.BranchAddr.ToString("X4") 1858 | End If 1859 | If syntax = 1 Then sBranchText = sBranchText.ToLower 1860 | pOpcode.OperandText = pOpcode.OperandText & " " & sBranchText 1861 | End If 1862 | 1863 | Return count 1864 | End Function 1865 | 1866 | Private Function TextVariable(pVariable As Integer, toSyntax As Integer) As String 1867 | If pVariable = 0 Then 1868 | If toSyntax = 0 Then Return "(SP)+" 1869 | If toSyntax = 1 Then Return "sp" 1870 | If toSyntax = 2 Then Return "STACK" 1871 | If toSyntax = 3 Then Return "sp" 1872 | End If 1873 | If pVariable < 16 Then 1874 | If toSyntax = 0 Then Return "L" & (pVariable - 1).ToString("X2") 1875 | If toSyntax = 1 Then Return "local" & (pVariable - 1).ToString 1876 | If toSyntax = 2 Then Return "L" & (pVariable - 1).ToString 1877 | If toSyntax = 3 Then Return "local" & (pVariable - 1).ToString 1878 | Else 1879 | End If 1880 | If pVariable < 256 Then 1881 | Dim value As Integer = pVariable - 16 1882 | If value > highest_global Then highest_global = value 1883 | usedGlobals.Add(value) 1884 | If toSyntax = 0 Then Return "G" & value.ToString("X2") 1885 | If toSyntax = 1 Then Return "g" & value.ToString 1886 | If toSyntax = 2 Then Return "G" & value.ToString 1887 | If toSyntax = 3 Then Return "g" & value.ToString 1888 | End If 1889 | Return "[Invalid variable: 0x" & pVariable.ToString("X2") & "]" 1890 | End Function 1891 | 1892 | Private Function TextNumber(pNumber As Integer, pLength As Integer, toSyntax As Integer, toSigned As Boolean) As String 1893 | If pLength = 1 Or (toSigned And syntax = 2) Then 1894 | Dim signedInt As Integer 1895 | If pNumber < 32768 Then 1896 | signedInt = pNumber 1897 | Else 1898 | signedInt = -1 * (65536 - pNumber) 1899 | End If 1900 | If toSyntax = 0 Then Return "0x" & pNumber.ToString("X2") 1901 | If toSyntax = 1 Then Return "0x" & pNumber.ToString("x2") 1902 | If toSyntax = 2 Then 1903 | If toSigned Then Return signedInt.ToString Else Return pNumber.ToString 1904 | End If 1905 | Else 1906 | If toSyntax = 0 Then Return "0x" & pNumber.ToString("X4") 1907 | If toSyntax = 1 Then Return "0x" & pNumber.ToString("x4") 1908 | If toSyntax = 2 Then Return pNumber.ToString 1909 | End If 1910 | Return pNumber.ToString 1911 | End Function 1912 | 1913 | Private Sub PrintLF(count As Integer) 1914 | If (count Mod 8) = 0 Then 1915 | If Not bSilent Then Console.WriteLine() 1916 | If Not bSilent Then Console.Write(" ") 1917 | End If 1918 | End Sub 1919 | End Class 1920 | --------------------------------------------------------------------------------