1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use anyhow::Result;
use clap::Parser;
use rascal::ProgramBuilder;
use rascal::{CompileOptions, FileSystemSourceProvider, SwfOptions};
use std::fs;
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "rascal", version, author, about)]
struct Opt {
/// A loose script (not class file) to add to the compiled program.
///
/// Multiple scripts may be added to one program.
/// Scripts will be executed in order that they are added, before any classes are loaded and after any raw pcode.
///
/// It is valid to not specify any scripts - if so, the entry point of the program will be the first
/// class (see `--class`) that contains a `static function main()` method.
#[arg(name = "SCRIPT", help_heading = "Inputs")]
script: Vec<PathBuf>,
/// Path to some raw pcode to add to the compiled program.
///
/// Multiple pcodes may be added to one program.
/// Pcodes will be executed in order that they are added, before any scripts are executed.
///
/// It is valid to not specify any scripts - if so, the entry point of the program will be the first
/// class (see `--class`) that contains a `static function main()` method.
#[arg(long, help_heading = "Inputs")]
pcode: Vec<PathBuf>,
/// Output file path. This will be overwritten if it already exists.
///
/// If not specified:
/// - If there are any scripts (see `SCRIPT`) specified, the first one will be used to determine the output path.
/// - `output.swf` will be used if all else fails.
#[arg(
short,
long,
verbatim_doc_comment,
help_heading = "Generated SWF Options"
)]
output: Option<PathBuf>,
/// A name of a class to be added to the compiled program.
///
/// This should be the canonical name of a class (e.g. `Foo` or `foo.bar.Baz`) which should be found in the current directory
/// (e.g. at `Foo.as` or `foo/bar/Baz.as`).
///
/// All classes will be loaded after any scripts (see `SCRIPT`).
/// If no scripts are specified, one (and only one) class is expected to have an entry point in
/// the form of a `static function main()` method.
#[arg(short, long, help_heading = "Inputs")]
class: Vec<String>,
/// Adds a directory to be searched for classes.
///
/// If no classpaths are specified, the current working directory will be used instead.
#[arg(long, long, help_heading = "Inputs")]
classpath: Vec<PathBuf>,
/// SWF version to use.
#[arg(
short = 'v',
long,
default_value_t = 15,
help_heading = "Generated SWF Options"
)]
swf_version: u8,
/// Frame rate of the output SWF.
#[arg(long, default_value_t = 24.0, help_heading = "Generated SWF Options")]
frame_rate: f32,
/// Whether the SWF uses the network sandbox.
/// If set, the SWF is allowed to make network requests but cannot access local files.
/// If not set, the SWF can access local files but cannot make network requests.
#[arg(long, help_heading = "Generated SWF Options")]
use_network_sandbox: bool,
}
fn main() -> Result<()> {
let mut opt = Opt::parse();
if opt.classpath.is_empty() {
opt.classpath.push(PathBuf::from("."));
}
let provider = FileSystemSourceProvider::with_roots(opt.classpath);
let mut builder = ProgramBuilder::new(provider)
.with_compile_options(CompileOptions::default().with_swf_version(opt.swf_version));
for src in &opt.pcode {
builder.add_pcode(&src.to_string_lossy());
}
for src in &opt.script {
builder.add_script(&src.to_string_lossy());
}
for class in &opt.class {
builder.add_class(class);
}
let parsed = builder.build().unwrap_or_else(|e| panic!("{}", e));
let pcode = parsed.compile();
let output_path = opt
.output
.or_else(|| opt.script.first().map(|s| s.with_extension("swf")))
.unwrap_or_else(|| PathBuf::from("output.swf"));
let swf = pcode.to_swf(
&SwfOptions::default()
.with_frame_rate(opt.frame_rate)
.with_network_sandbox(opt.use_network_sandbox),
)?;
fs::write(&output_path, swf)?;
Ok(())
}