├── 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 |
--------------------------------------------------------------------------------