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