Class: R3EXS::StringsInjector

Inherits:
Prism::Visitor
  • Object
show all
Defined in:
lib/R3EXS/ast.rb

Overview

用来替换源码里面的字符串和符号

Defined Under Namespace

Classes: Location

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(script, hash) ⇒ StringsInjector

初始化 StringsInjector

Parameters:



134
135
136
137
138
139
140
# File 'lib/R3EXS/ast.rb', line 134

def initialize(script, hash)
  super()
  @content_loc = []
  @script = script
  @strings_hash = hash
  @root_node = Prism.parse(script).value
end

Instance Attribute Details

#content_loc ⇒ Array<Location> (readonly)

字符串在二进制源文件中的位置

Returns:



80
81
82
# File 'lib/R3EXS/ast.rb', line 80

def content_loc
  @content_loc
end

#root_node ⇒ Prism::Node (readonly)

AST 根节点

Returns:

  • (Prism::Node)


95
96
97
# File 'lib/R3EXS/ast.rb', line 95

def root_node
  @root_node
end

#script ⇒ String (readonly)

Ruby 源码

Returns:



85
86
87
# File 'lib/R3EXS/ast.rb', line 85

def script
  @script
end

#strings_hash ⇒ Hash{String => String} (readonly)

字符串翻译表

Returns:



90
91
92
# File 'lib/R3EXS/ast.rb', line 90

def strings_hash
  @strings_hash
end

Class Method Details

.inject(script, hash) ⇒ String

将 script 源码中的字符串替换成 @strings_hash 翻译后的字符串

Parameters:

Returns:



204
205
206
207
# File 'lib/R3EXS/ast.rb', line 204

def self.inject(script, hash)
  injector = new(script, hash)
  injector.inject
end

Instance Method Details

#inject ⇒ String

将 script 源码中的字符串替换成 @strings_hash 翻译后的字符串

Returns:



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/R3EXS/ast.rb', line 176

def inject
  code = []
  # 首先遍历一遍,找到所有需要替换的字符串的位置
  visit(@root_node)

  # 然后开始替换 code 中的字符串
  # 先将 @content_loc 按照 start_offset 从小到大排序
  @content_loc.sort_by!(&:start_offset)

  # 然后将 code 切片,将字符串替换成新的字符串
  # 注意 Prism.parse 得到的位置是字节的偏移量,而 UTF-8 是变长编码,所以需要使用 byteslice 来切片
  start_offset = 0
  @content_loc.each do |loc|
    code << @script.byteslice(start_offset...loc.start_offset)
    code << @strings_hash[loc.content]
    start_offset = loc.start_offset + loc.length
  end
  code << @script.byteslice(start_offset..)

  code.join
end

#visit_string_node(node) ⇒ void

This method returns an undefined value.

处理类型为 StringNode 的节点

Parameters:

  • node (Prism::StringNode) —

    AST 节点



147
148
149
150
151
152
153
154
# File 'lib/R3EXS/ast.rb', line 147

def visit_string_node(node)
  location = node.content_loc
  value = location.slice
  if @strings_hash.key?(value) && @strings_hash[value].to_s != ''
    @content_loc << Location.new(location.start_offset, location.length, value)
  end
  super
end

#visit_symbol_node(node) ⇒ void

This method returns an undefined value.

处理类型为 SymbolNode 的节点

Parameters:

  • node (Prism::SymbolNode) —

    AST 节点



161
162
163
164
165
166
167
168
169
170
171
# File 'lib/R3EXS/ast.rb', line 161

def visit_symbol_node(node)
  location = node.value_loc
  # 如果 location 不为 nil,说明这个符号是一个字符串
  if location
    value = location.slice
    if @strings_hash.key?(value) && @strings_hash[value].to_s != ''
      @content_loc << Location.new(location.start_offset, location.length, value)
    end
  end
  super
end