unidecompiler-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- unidecompiler_cli-0.1.0/PKG-INFO +21 -0
- unidecompiler_cli-0.1.0/README.md +13 -0
- unidecompiler_cli-0.1.0/pyproject.toml +17 -0
- unidecompiler_cli-0.1.0/setup.cfg +4 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli/__init__.py +1 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli/cli.py +142 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli/input_sources.py +6 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli.egg-info/PKG-INFO +21 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli.egg-info/SOURCES.txt +11 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli.egg-info/dependency_links.txt +1 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli.egg-info/entry_points.txt +2 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli.egg-info/requires.txt +1 -0
- unidecompiler_cli-0.1.0/src/unidecompiler_cli.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: unidecompiler-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Command-line host for unidecompiler plugins
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: unidecompiler<0.2.0,>=0.1.0
|
|
8
|
+
|
|
9
|
+
# unidecompiler-cli
|
|
10
|
+
|
|
11
|
+
`unidecompiler-cli` is the command-line host for installed `unidecompiler`
|
|
12
|
+
frontend plugins. It discovers plugins through the `unidecompiler.frontends`
|
|
13
|
+
entry-point group and uses the public `DecompilerEngine` facade.
|
|
14
|
+
|
|
15
|
+
Install the CLI and one or more frontend packages:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
python -m pip install unidecompiler-cli unidecompiler-plugin-python-pyc
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Run `unidecompiler --help` for command-line usage.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# unidecompiler-cli
|
|
2
|
+
|
|
3
|
+
`unidecompiler-cli` is the command-line host for installed `unidecompiler`
|
|
4
|
+
frontend plugins. It discovers plugins through the `unidecompiler.frontends`
|
|
5
|
+
entry-point group and uses the public `DecompilerEngine` facade.
|
|
6
|
+
|
|
7
|
+
Install the CLI and one or more frontend packages:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
python -m pip install unidecompiler-cli unidecompiler-plugin-python-pyc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run `unidecompiler --help` for command-line usage.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "unidecompiler-cli"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Command-line host for unidecompiler plugins"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
dependencies = ["unidecompiler>=0.1.0,<0.2.0"]
|
|
12
|
+
|
|
13
|
+
[project.scripts]
|
|
14
|
+
unidecompiler = "unidecompiler_cli.cli:main"
|
|
15
|
+
|
|
16
|
+
[tool.setuptools.packages.find]
|
|
17
|
+
where = ["src"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command-line host for installed unidecompiler frontend plugins."""
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import base64
|
|
5
|
+
from dataclasses import fields, is_dataclass
|
|
6
|
+
import json
|
|
7
|
+
import math
|
|
8
|
+
import sys
|
|
9
|
+
from typing import Any
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from unidecompiler.backends.pseudocode import GenericPseudocodeBackend
|
|
13
|
+
from unidecompiler.core.astify import module_to_ast
|
|
14
|
+
from unidecompiler.plugin_registry import FrontendRegistry, FrontendSelectionError
|
|
15
|
+
from unidecompiler.plugins import FrontendDecodeError
|
|
16
|
+
from unidecompiler.input_sources import expand_input_path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main(argv: list[str] | None = None, *, registry: FrontendRegistry | None = None) -> int:
|
|
20
|
+
parser = argparse.ArgumentParser(
|
|
21
|
+
prog="unidecompiler",
|
|
22
|
+
description="Decompile bytecode into generic pseudocode.",
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument("input", nargs="?", help="input bytecode file")
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--frontend",
|
|
27
|
+
help="explicit frontend plugin id, e.g. lua",
|
|
28
|
+
default=None,
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--versions",
|
|
32
|
+
action="store_true",
|
|
33
|
+
help="print supported frontend version matrix",
|
|
34
|
+
)
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"--format",
|
|
37
|
+
choices=("pseudocode", "ast-json"),
|
|
38
|
+
default="pseudocode",
|
|
39
|
+
help="output format (default: pseudocode)",
|
|
40
|
+
)
|
|
41
|
+
args = parser.parse_args(argv)
|
|
42
|
+
|
|
43
|
+
registry = registry or FrontendRegistry.discover()
|
|
44
|
+
if args.versions:
|
|
45
|
+
for plugin, support in registry.version_support():
|
|
46
|
+
versions = ", ".join(support.versions)
|
|
47
|
+
print(
|
|
48
|
+
f"{plugin.id}: {support.family} | {versions} | "
|
|
49
|
+
f"{support.status} | parser: {support.parser}"
|
|
50
|
+
)
|
|
51
|
+
return 0
|
|
52
|
+
|
|
53
|
+
if args.input is None:
|
|
54
|
+
parser.error("input is required unless --versions is used")
|
|
55
|
+
input_path = Path(args.input)
|
|
56
|
+
artifacts = expand_input_path(input_path)
|
|
57
|
+
if not artifacts:
|
|
58
|
+
raise SystemExit(f"no input files found in {input_path}")
|
|
59
|
+
|
|
60
|
+
backend = GenericPseudocodeBackend() if args.format == "pseudocode" else None
|
|
61
|
+
ast_modules: list[dict[str, Any]] = []
|
|
62
|
+
processed = 0
|
|
63
|
+
for artifact in artifacts:
|
|
64
|
+
if artifact.kind == "resource":
|
|
65
|
+
print(f"resource: {artifact.display_path}", file=sys.stderr)
|
|
66
|
+
continue
|
|
67
|
+
try:
|
|
68
|
+
frontend = registry.select(
|
|
69
|
+
artifact.data, artifact.display_path, explicit_id=args.frontend
|
|
70
|
+
)
|
|
71
|
+
except FrontendSelectionError:
|
|
72
|
+
print(f"resource: {artifact.display_path}", file=sys.stderr)
|
|
73
|
+
continue
|
|
74
|
+
try:
|
|
75
|
+
decoded = frontend.decode(artifact.data, artifact.display_path)
|
|
76
|
+
except FrontendDecodeError:
|
|
77
|
+
print(f"resource: {artifact.display_path}", file=sys.stderr)
|
|
78
|
+
continue
|
|
79
|
+
try:
|
|
80
|
+
module = frontend.lift(decoded)
|
|
81
|
+
if args.format == "ast-json":
|
|
82
|
+
ast_modules.append(_json_value(module_to_ast(module)))
|
|
83
|
+
else:
|
|
84
|
+
assert backend is not None
|
|
85
|
+
emitted = backend.emit(module)
|
|
86
|
+
print(emitted.text)
|
|
87
|
+
except Exception as error:
|
|
88
|
+
print(
|
|
89
|
+
f"error: {artifact.display_path}: {type(error).__name__}: {error}",
|
|
90
|
+
file=sys.stderr,
|
|
91
|
+
)
|
|
92
|
+
continue
|
|
93
|
+
processed += 1
|
|
94
|
+
|
|
95
|
+
if processed == 0:
|
|
96
|
+
raise SystemExit(f"no supported input files found in {input_path}")
|
|
97
|
+
if args.format == "ast-json":
|
|
98
|
+
print(
|
|
99
|
+
json.dumps(
|
|
100
|
+
{"schema_version": 1, "modules": ast_modules},
|
|
101
|
+
ensure_ascii=False,
|
|
102
|
+
sort_keys=True,
|
|
103
|
+
allow_nan=False,
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _json_value(value: Any) -> Any:
|
|
110
|
+
"""Convert the generic AST dataclasses into a JSON-compatible tree."""
|
|
111
|
+
if is_dataclass(value):
|
|
112
|
+
return {
|
|
113
|
+
"node_type": type(value).__name__,
|
|
114
|
+
**{field.name: _json_value(getattr(value, field.name)) for field in fields(value)},
|
|
115
|
+
}
|
|
116
|
+
if isinstance(value, bytes | bytearray | memoryview):
|
|
117
|
+
return {
|
|
118
|
+
"value_type": "bytes",
|
|
119
|
+
"base64": base64.b64encode(bytes(value)).decode("ascii"),
|
|
120
|
+
}
|
|
121
|
+
if isinstance(value, complex):
|
|
122
|
+
return {"value_type": "complex", "real": value.real, "imag": value.imag}
|
|
123
|
+
if isinstance(value, float) and not math.isfinite(value):
|
|
124
|
+
return {"value_type": "float", "value": repr(value)}
|
|
125
|
+
if isinstance(value, tuple | list):
|
|
126
|
+
return [_json_value(item) for item in value]
|
|
127
|
+
if isinstance(value, dict):
|
|
128
|
+
if all(isinstance(key, str) for key in value):
|
|
129
|
+
return {key: _json_value(item) for key, item in value.items()}
|
|
130
|
+
return {
|
|
131
|
+
"value_type": "map",
|
|
132
|
+
"entries": [[_json_value(key), _json_value(item)] for key, item in value.items()],
|
|
133
|
+
}
|
|
134
|
+
if isinstance(value, set | frozenset):
|
|
135
|
+
return {"value_type": "set", "items": [_json_value(item) for item in sorted(value, key=repr)]}
|
|
136
|
+
if value is None or isinstance(value, str | int | float | bool):
|
|
137
|
+
return value
|
|
138
|
+
raise TypeError(f"AST JSON cannot encode {type(value).__name__}")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
if __name__ == "__main__":
|
|
142
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Compatibility import for the library-owned input expansion API."""
|
|
4
|
+
from unidecompiler.input_sources import ARCHIVE_SUFFIXES, InputArtifact, expand_input_path, iter_input_path
|
|
5
|
+
|
|
6
|
+
__all__ = ("ARCHIVE_SUFFIXES", "InputArtifact", "expand_input_path", "iter_input_path")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: unidecompiler-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Command-line host for unidecompiler plugins
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: unidecompiler<0.2.0,>=0.1.0
|
|
8
|
+
|
|
9
|
+
# unidecompiler-cli
|
|
10
|
+
|
|
11
|
+
`unidecompiler-cli` is the command-line host for installed `unidecompiler`
|
|
12
|
+
frontend plugins. It discovers plugins through the `unidecompiler.frontends`
|
|
13
|
+
entry-point group and uses the public `DecompilerEngine` facade.
|
|
14
|
+
|
|
15
|
+
Install the CLI and one or more frontend packages:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
python -m pip install unidecompiler-cli unidecompiler-plugin-python-pyc
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Run `unidecompiler --help` for command-line usage.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/unidecompiler_cli/__init__.py
|
|
4
|
+
src/unidecompiler_cli/cli.py
|
|
5
|
+
src/unidecompiler_cli/input_sources.py
|
|
6
|
+
src/unidecompiler_cli.egg-info/PKG-INFO
|
|
7
|
+
src/unidecompiler_cli.egg-info/SOURCES.txt
|
|
8
|
+
src/unidecompiler_cli.egg-info/dependency_links.txt
|
|
9
|
+
src/unidecompiler_cli.egg-info/entry_points.txt
|
|
10
|
+
src/unidecompiler_cli.egg-info/requires.txt
|
|
11
|
+
src/unidecompiler_cli.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
unidecompiler<0.2.0,>=0.1.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
unidecompiler_cli
|