R3EXS 1.1.1 → 2.0.0

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.
data/lib/R3EXS/ast.rb CHANGED
@@ -1,158 +1,209 @@
1
- # frozen_string_literal: true
2
-
3
- require 'prism'
4
-
5
- module R3EXS
6
-
7
- # 用来提取源码生成的 AST 中的字符串和符号
8
- class StringsExtractor < Prism::Visitor
9
-
10
- # 提取后存储的字符串数组
11
- #
12
- # @return [Array<String>]
13
- attr_reader :strings
14
-
15
- # 是否包含脚本中的符号
16
- #
17
- # @return [Boolean]
18
- attr_reader :with_symbol
19
-
20
- # 初始化 StringsExtractor
21
- #
22
- # @param strings [Array<String>] 存储提取出的字符串的数组
23
- # @param with_symbol [Boolean] 是否包含脚本中的符号
24
- #
25
- # @return [StringsExtractor]
26
- def initialize(strings, with_symbol)
27
- @strings = strings
28
- @with_symbol = with_symbol
29
- end
30
-
31
- # 处理类型为 StringNode 的节点
32
- #
33
- # @param node [Prism::StringNode] AST 节点
34
- #
35
- # @return [void]
36
- def visit_string_node(node)
37
- @strings << node.content
38
- super
39
- end
40
-
41
- # 处理类型为 SymbolNode 的节点
42
- #
43
- # @param node [Prism::SymbolNode] AST 节点
44
- #
45
- # @return [void]
46
- def visit_symbol_node(node)
47
- @strings << node.value if @with_symbol
48
- super
49
- end
50
- end
51
-
52
- # 用来替换源码里面的字符串和符号
53
- class StringsInjector < Prism::Visitor
54
-
55
- # 用来记录字符串的位置
56
- class Location
57
-
58
- # 字符串在二进制源文件中的起始位置
59
- #
60
- # @return [Integer]
61
- attr_reader :start_offset
62
-
63
- # 字符串的长度
64
- #
65
- # @return [Integer]
66
- attr_reader :length
67
-
68
- # 字符串内容
69
- #
70
- # @return [String]
71
- attr_reader :content
72
-
73
- # @note start_offset 是字符串在二进制下打开时的位置
74
- #
75
- # @param start_offset [Integer] 字符串在源文件中的起始位置
76
- # @param length [Integer] 字符串的长度
77
- # @param content [String] 字符串内容
78
- #
79
- # @return [Location]
80
- def initialize(start_offset, length, content)
81
- @start_offset = start_offset
82
- @length = length
83
- @content = content
84
- end
85
- end
86
-
87
- # 初始化 StringsInjector
88
- #
89
- # @param hash [Hash<String, String>] 字符串翻译表
90
- #
91
- # @return [StringsInjector]
92
- def initialize(hash)
93
- @strings_hash = hash
94
- @content_loc = []
95
- @code = []
96
- end
97
-
98
- # 处理类型为 StringNode 的节点
99
- #
100
- # @param node [Prism::StringNode] AST 节点
101
- #
102
- # @return [void]
103
- def visit_string_node(node)
104
- location = node.content_loc
105
- value = location.slice
106
- if @strings_hash.has_key?(value) && @strings_hash[value].to_s != ''
107
- @content_loc << Location.new(location.start_offset, location.length, value)
108
- end
109
- super
110
- end
111
-
112
- # 处理类型为 SymbolNode 的节点
113
- #
114
- # @param node [Prism::SymbolNode] AST 节点
115
- #
116
- # @return [void]
117
- def visit_symbol_node(node)
118
- location = node.value_loc
119
- # 如果 location 不为 nil,说明这个符号是一个字符串
120
- if location
121
- value = location.slice
122
- if @strings_hash.has_key?(value) && @strings_hash[value].to_s != ''
123
- @content_loc << Location.new(location.start_offset, location.length, value)
124
- end
125
- end
126
- super
127
- end
128
-
129
- # 将 script 源码中的字符串替换成 @strings_hash 翻译后的字符串
130
- #
131
- # @param script [String] Ruby 源码,以二进制编码打开
132
- # @param ast_root [Prism::ProgramNode] AST 树根节点
133
- #
134
- # @return [String]
135
- def rewrite(script, ast_root)
136
- # 首先遍历一遍,找到所有需要替换的字符串的位置
137
- visit(ast_root)
138
-
139
- # 然后开始替换 code 中的字符串
140
- # 先将 @content_loc 按照 start_offset 从小到大排序
141
- @content_loc.sort_by! { |loc| loc.start_offset }
142
-
143
- # 然后将 code 切片,将字符串替换成新的字符串
144
- start_offset = 0
145
- @content_loc.each do |loc|
146
- @code << script[start_offset...loc.start_offset]
147
- @code << @strings_hash[loc.content]
148
- start_offset = loc.start_offset + loc.length
149
- end
150
- @code << script[start_offset..-1]
151
-
152
- # 将 @code 里面的字符串全部改为二进制编码
153
- @code.map! { |str| str.force_encoding('ASCII-8BIT') unless str.nil? }
154
- @code.join
155
- end
156
- end
157
-
158
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'prism'
4
+
5
+ module R3EXS
6
+ # 用来提取源码生成的 AST 中的字符串和符号
7
+ class StringsExtractor < Prism::Visitor
8
+ # 提取后存储的字符串数组
9
+ #
10
+ # @return [Array<String>]
11
+ attr_reader :strings
12
+
13
+ # 是否包含脚本中的符号
14
+ #
15
+ # @return [Boolean]
16
+ attr_reader :with_symbol
17
+
18
+ # AST 根节点
19
+ #
20
+ # @return [Prism::Node]
21
+ attr_reader :root_node
22
+
23
+ # 初始化 StringsExtractor
24
+ #
25
+ # @param script [String] Ruby 源码
26
+ # @param with_symbol [Boolean] 是否包含脚本中的符号
27
+ #
28
+ # @return [StringsExtractor]
29
+ def initialize(script, with_symbol)
30
+ super()
31
+ @strings = []
32
+ @with_symbol = with_symbol
33
+ @root_node = Prism.parse(script).value
34
+ end
35
+
36
+ # 处理类型为 StringNode 的节点
37
+ #
38
+ # @param node [Prism::StringNode] AST 节点
39
+ #
40
+ # @return [void]
41
+ def visit_string_node(node)
42
+ @strings << node.content
43
+ super
44
+ end
45
+
46
+ # 处理类型为 SymbolNode 的节点
47
+ #
48
+ # @param node [Prism::SymbolNode] AST 节点
49
+ #
50
+ # @return [void]
51
+ def visit_symbol_node(node)
52
+ @strings << node.value if @with_symbol
53
+ super
54
+ end
55
+
56
+ # 提取 script 源码中的字符串
57
+ #
58
+ # @return [Array<String>]
59
+ def extract
60
+ visit(@root_node)
61
+ @strings
62
+ end
63
+
64
+ # 提取 script 源码中的字符串
65
+ # @param script [String] Ruby 源码
66
+ # @param with_symbol [Boolean] 是否包含脚本中的符号
67
+ #
68
+ # @return [Array<String>]
69
+ def self.extract(script, with_symbol)
70
+ extractor = new(script, with_symbol)
71
+ extractor.extract
72
+ end
73
+ end
74
+
75
+ # 用来替换源码里面的字符串和符号
76
+ class StringsInjector < Prism::Visitor
77
+ # 字符串在二进制源文件中的位置
78
+ #
79
+ # @return [Array<Location>]
80
+ attr_reader :content_loc
81
+
82
+ # Ruby 源码
83
+ #
84
+ # @return [String]
85
+ attr_reader :script
86
+
87
+ # 字符串翻译表
88
+ #
89
+ # @return [Hash{String => String}]
90
+ attr_reader :strings_hash
91
+
92
+ # AST 根节点
93
+ #
94
+ # @return [Prism::Node]
95
+ attr_reader :root_node
96
+
97
+ # 用来记录字符串的位置
98
+ class Location
99
+ # 字符串在二进制源文件中的起始位置
100
+ #
101
+ # @return [Integer]
102
+ attr_reader :start_offset
103
+
104
+ # 字符串的长度
105
+ #
106
+ # @return [Integer]
107
+ attr_reader :length
108
+
109
+ # 字符串内容
110
+ #
111
+ # @return [String]
112
+ attr_reader :content
113
+
114
+ # @note start_offset 是字符串在二进制下打开时的位置
115
+ #
116
+ # @param start_offset [Integer] 字符串在源文件中的起始位置
117
+ # @param length [Integer] 字符串的长度
118
+ # @param content [String] 字符串内容
119
+ #
120
+ # @return [Location]
121
+ def initialize(start_offset, length, content)
122
+ @start_offset = start_offset
123
+ @length = length
124
+ @content = content
125
+ end
126
+ end
127
+
128
+ # 初始化 StringsInjector
129
+ #
130
+ # @param script [String] Ruby 源码
131
+ # @param hash [Hash{String => String}] 字符串翻译表
132
+ #
133
+ # @return [StringsInjector]
134
+ def initialize(script, hash)
135
+ super()
136
+ @content_loc = []
137
+ @script = script
138
+ @strings_hash = hash
139
+ @root_node = Prism.parse(script).value
140
+ end
141
+
142
+ # 处理类型为 StringNode 的节点
143
+ #
144
+ # @param node [Prism::StringNode] AST 节点
145
+ #
146
+ # @return [void]
147
+ def visit_string_node(node)
148
+ location = node.content_loc
149
+ value = location.slice
150
+ if @strings_hash.key?(value) && @strings_hash[value].to_s != ''
151
+ @content_loc << Location.new(location.start_offset, location.length, value)
152
+ end
153
+ super
154
+ end
155
+
156
+ # 处理类型为 SymbolNode 的节点
157
+ #
158
+ # @param node [Prism::SymbolNode] AST 节点
159
+ #
160
+ # @return [void]
161
+ def visit_symbol_node(node)
162
+ location = node.value_loc
163
+ # 如果 location 不为 nil,说明这个符号是一个字符串
164
+ if location
165
+ value = location.slice
166
+ if @strings_hash.key?(value) && @strings_hash[value].to_s != ''
167
+ @content_loc << Location.new(location.start_offset, location.length, value)
168
+ end
169
+ end
170
+ super
171
+ end
172
+
173
+ # 将 script 源码中的字符串替换成 @strings_hash 翻译后的字符串
174
+ #
175
+ # @return [String]
176
+ def inject
177
+ code = []
178
+ # 首先遍历一遍,找到所有需要替换的字符串的位置
179
+ visit(@root_node)
180
+
181
+ # 然后开始替换 code 中的字符串
182
+ # 先将 @content_loc 按照 start_offset 从小到大排序
183
+ @content_loc.sort_by!(&:start_offset)
184
+
185
+ # 然后将 code 切片,将字符串替换成新的字符串
186
+ # 注意 Prism.parse 得到的位置是字节的偏移量,而 UTF-8 是变长编码,所以需要使用 byteslice 来切片
187
+ start_offset = 0
188
+ @content_loc.each do |loc|
189
+ code << @script.byteslice(start_offset...loc.start_offset)
190
+ code << @strings_hash[loc.content]
191
+ start_offset = loc.start_offset + loc.length
192
+ end
193
+ code << @script.byteslice(start_offset..)
194
+
195
+ code.join
196
+ end
197
+
198
+ # 将 script 源码中的字符串替换成 @strings_hash 翻译后的字符串
199
+ #
200
+ # @param script [String] Ruby 源码
201
+ # @param hash [Hash{String => String}] 字符串翻译表
202
+ #
203
+ # @return [String]
204
+ def self.inject(script, hash)
205
+ injector = new(script, hash)
206
+ injector.inject
207
+ end
208
+ end
209
+ end
data/lib/R3EXS/error.rb CHANGED
@@ -1,245 +1,39 @@
1
- # frozen_string_literal: true
2
-
3
- module R3EXS
4
-
5
- # 用来处理 RPG 模块下的类型错误的异常
6
- class RPGTypeError < TypeError
7
-
8
- # 引发异常的类
9
- #
10
- # @return [Object]
11
- attr_reader :obj
12
-
13
- # 初始化 RPGTypeError
14
- #
15
- # @param msg [String] 异常信息
16
- # @param obj [Object] 引发异常的类
17
- #
18
- # @return [RPGTypeError]
19
- def initialize(msg = '', obj)
20
- super(msg)
21
- @obj = obj
22
- end
23
- end
24
-
25
- # 用来处理 R3EXS 模块下的类型错误的异常
26
- class R3EXSTypeError < TypeError
27
-
28
- # 引发异常的类型
29
- #
30
- # @return [Object]
31
- attr_reader :obj
32
-
33
- # 初始化 R3EXSTypeError
34
- #
35
- # @param msg [String] 异常信息
36
- # @param obj [Object] 引发异常的的类型
37
- #
38
- # @return [R3EXSTypeError]
39
- def initialize(msg = '', obj)
40
- super(msg)
41
- @obj = obj
42
- end
43
- end
44
-
45
- # 用来处理 Game.rgss3a 文件加密格式不支持的异常
46
- class RGSS3AFileError < StandardError
47
-
48
- # 引发异常的 rgss3a 文件路径
49
- #
50
- # @return [String]
51
- attr_reader :rgss3a_path
52
-
53
- # 初始化 RGSS3AFileError
54
- #
55
- # @param msg [String] 异常信息
56
- # @param rgss3a_path [String] 引发异常的 rgss3a 文件路径
57
- #
58
- # @return [Rvdata2DirError]
59
- def initialize(msg = '', rgss3a_path)
60
- super(msg)
61
- @rgss3a_path = rgss3a_path
62
- end
63
- end
64
-
65
- # 用来处理 rvdata2 文件损坏的异常
66
- class Rvdata2FileError < StandardError
67
-
68
- # 引发异常的 rvdata2 文件路径
69
- #
70
- # @return [String]
71
- attr_reader :rvdata2_path
72
-
73
- # 初始化 Rvdata2FileError
74
- #
75
- # @param msg [String] 异常信息
76
- # @param rvdata2_path [String] 引发异常的 rvdata2 文件路径
77
- #
78
- # @return [Rvdata2DirError]
79
- def initialize(msg = '', rvdata2_path)
80
- super(msg)
81
- @rvdata2_path = rvdata2_path
82
- end
83
- end
84
-
85
- # 用来处理 RPG 模块下 JSON 文件损坏的异常
86
- class RPGJsonFileError < StandardError
87
-
88
- # 引发异常的 json 文件路径
89
- #
90
- # @return [String]
91
- attr_reader :json_path
92
-
93
- # 初始化 RPGJsonFileError
94
- #
95
- # @param msg [String] 异常信息
96
- # @param json_path [String] 引发异常的 json 文件路径
97
- #
98
- # @return [RPGJsonFileError]
99
- def initialize(msg = '', json_path)
100
- super(msg)
101
- @json_path = json_path
102
- end
103
- end
104
-
105
- # 用来处理 R3EXS 模块下 JSON 文件损坏的异常
106
- class R3EXSJsonFileError < StandardError
107
-
108
- # 引发异常的 json 文件路径
109
- #
110
- # @return [String]
111
- attr_reader :json_path
112
-
113
- # 初始化 R3EXSJsonFileError
114
- #
115
- # @param msg [String] 异常信息
116
- # @param json_path [String] 引发异常的 json 文件路径
117
- #
118
- # @return [R3EXSJsonFileError]
119
- def initialize(msg = '', json_path)
120
- super(msg)
121
- @json_path = json_path
122
- end
123
- end
124
-
125
- # 用来处理模块名错误的异常
126
- class ModuleNameError < ArgumentError
127
-
128
- # 引发异常的模块名
129
- #
130
- # @return [Symbol]
131
- attr_reader :module_name
132
-
133
- # 初始化 ModuleNameError
134
- #
135
- # @param msg [String] 异常信息
136
- # @param module_name [Symbol] 引发异常的模块名
137
- #
138
- # @return [ModuleNameError]
139
- def initialize(msg = '', module_name)
140
- super(msg)
141
- @module_name = module_name
142
- end
143
- end
144
-
145
- # 用来处理文件名错误的异常
146
- class FileBaseNameError < ArgumentError
147
-
148
- # 引发异常的文件名
149
- #
150
- # @return [String]
151
- attr_reader :filebasename
152
-
153
- # 初始化 FileBaseNameError
154
- #
155
- # @param msg [String] 异常信息
156
- # @param filebasename [String] 引发异常的文件名
157
- #
158
- # @return [FileBaseNameError]
159
- def initialize(msg = '', filebasename)
160
- super(msg)
161
- @filebasename = filebasename
162
- end
163
- end
164
-
165
- # 用来处理 *.rvdata2 文件目录不存在的异常
166
- class Rvdata2DirError < IOError
167
-
168
- # 引发异常的 *.rvdata2 文件目录
169
- #
170
- # @return [String]
171
- attr_reader :rvdata2_dir
172
-
173
- # 初始化 Rvdata2DirError
174
- #
175
- # @param msg [String] 异常信息
176
- # @param rvdata2_dir [String] 引发异常的 *.rvdata2 文件目录
177
- #
178
- # @return [Rvdata2DirError]
179
- def initialize(msg = '', rvdata2_dir)
180
- super(msg)
181
- @rvdata2_dir = rvdata2_dir
182
- end
183
- end
184
-
185
- # 用来处理 *.json 文件目录不存在的异常
186
- class JsonDirError < IOError
187
-
188
- # 引发异常的 *.json 文件目录
189
- #
190
- # @return [String]
191
- attr_reader :json_dir
192
-
193
- # 初始化 JsonDirError
194
- #
195
- # @param msg [String] 异常信息
196
- # @param json_dir [String] 引发异常的 *.json 文件目录
197
- #
198
- # @return [JsonDirError]
199
- def initialize(msg = '', json_dir)
200
- super(msg)
201
- @json_dir = json_dir
202
- end
203
- end
204
-
205
- # 用来处理 Scripts_info.json 文件不存在的异常
206
- class ScriptsInfoPathError < IOError
207
-
208
- # 引发异常的 Scripts_info.json 文件路径
209
- #
210
- # @return [String]
211
- attr_reader :scripts_info_path
212
-
213
- # 初始化 ScriptsInfoPathError
214
- #
215
- # @param msg [String] 异常信息
216
- # @param scripts_info_path [String] 引发异常的 Scripts_info.json 文件路径
217
- #
218
- # @return [ScriptsInfoPathError]
219
- def initialize(msg = '', scripts_info_path)
220
- super(msg)
221
- @scripts_info_path = scripts_info_path
222
- end
223
- end
224
-
225
- # 用来处理 ManualTransFile.json 文件不存在的异常
226
- class ManualTransFilePathError < IOError
227
-
228
- # 引发异常的 ManualTransFile.json 文件路径
229
- #
230
- # @return [String]
231
- attr_reader :manualtransfile_path
232
-
233
- # 初始化 ManualTransFilePathError
234
- #
235
- # @param msg [String] 异常信息
236
- # @param manualtransfile_path [String] 引发异常的 ManualTransFile.json 文件路径
237
- #
238
- # @return [ManualTransFilePathError]
239
- def initialize(msg = '', manualtransfile_path)
240
- super(msg)
241
- @manualtransfile_path = manualtransfile_path
242
- end
243
- end
244
-
245
- end
1
+ # frozen_string_literal: true
2
+
3
+ module R3EXS
4
+ # 用来处理 Game.rgss3a 文件加密格式不支持的异常
5
+ class RGSS3AFileError < StandardError
6
+ end
7
+
8
+ # 用来处理 RPG 模块下 JSON 文件损坏的异常
9
+ class RPGJsonFileError < StandardError
10
+ end
11
+
12
+ # 用来处理 R3EXS 模块下 JSON 文件损坏的异常
13
+ class R3EXSJsonFileError < StandardError
14
+ end
15
+
16
+ # 用来处理模块名错误的异常
17
+ class ModuleNameError < ArgumentError
18
+ end
19
+
20
+ # 用来处理 *.rvdata2 文件目录不存在的异常
21
+ class Rvdata2DirError < IOError
22
+ end
23
+
24
+ # 用来处理 *.json 文件目录不存在的异常
25
+ class JsonDirError < IOError
26
+ end
27
+
28
+ # 用来处理 Rvdata2 文件不存在的异常
29
+ class Rvdata2PathError < IOError
30
+ end
31
+
32
+ # 用来处理 Scripts_info.json 文件不存在的异常
33
+ class ScriptsInfoPathError < IOError
34
+ end
35
+
36
+ # 用来处理 ManualTransFile.json 文件不存在的异常
37
+ class ManualTransFilePathError < IOError
38
+ end
39
+ end