NCPrePatcher 0.2.0-x64-mingw-ucrt

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.
@@ -0,0 +1,440 @@
1
+ require 'ffi'
2
+
3
+ module NitroBind
4
+ extend FFI::Library
5
+ ffi_lib [
6
+ File.expand_path("nitro", __dir__),
7
+ File.expand_path("nitro.dylib", __dir__),
8
+ File.expand_path("nitro.so", __dir__),
9
+ ]
10
+
11
+ typedef :pointer, :rom_handle
12
+ typedef :pointer, :header_handle
13
+ typedef :pointer, :codebin_handle
14
+ typedef :pointer, :ovte_handle
15
+ typedef :pointer, :module_params_handle
16
+
17
+ attach_function :nitroRom_alloc, [], :rom_handle
18
+ attach_function :nitroRom_release, [:rom_handle], :void
19
+ attach_function :nitroRom_load, [:rom_handle, :string], :bool
20
+ attach_function :nitroRom_getSize, [:rom_handle], :size_t
21
+ attach_function :nitroRom_getHeader, [:rom_handle], :header_handle
22
+ attach_function :nitroRom_getFile, [:rom_handle, :uint32], :pointer
23
+ attach_function :nitroRom_getFileSize, [:rom_handle, :uint32], :uint32
24
+ attach_function :nitroRom_loadArm9, [:rom_handle], :codebin_handle
25
+ attach_function :nitroRom_loadArm7, [:rom_handle], :codebin_handle
26
+ attach_function :nitroRom_loadOverlay, [:rom_handle, :uint32], :codebin_handle
27
+ attach_function :nitroRom_getOverlayCount, [:rom_handle], :uint32
28
+ attach_function :nitroRom_getArm9OvT, [:rom_handle], :ovte_handle
29
+
30
+ attach_function :headerBin_alloc, [], :header_handle
31
+ attach_function :headerBin_release, [:header_handle], :void
32
+ attach_function :headerBin_load, [:header_handle, :string], :bool
33
+ attach_function :headerBin_getGameTitle, [:header_handle], :string
34
+ attach_function :headerBin_getGameCode, [:header_handle], :string
35
+ attach_function :headerBin_getMakerCode, [:header_handle], :string
36
+ attach_function :headerBin_getArm9AutoLoadHookOffset, [:header_handle], :uint32
37
+ attach_function :headerBin_getArm7AutoLoadHookOffset, [:header_handle], :uint32
38
+ attach_function :headerBin_getArm9EntryAddress, [:header_handle], :uint32
39
+ attach_function :headerBin_getArm7EntryAddress, [:header_handle], :uint32
40
+ attach_function :headerBin_getArm9RamAddress, [:header_handle], :uint32
41
+ attach_function :headerBin_getArm7RamAddress, [:header_handle], :uint32
42
+ attach_function :headerBin_getArm9OvTSize, [:header_handle], :uint32
43
+
44
+ attach_function :codeBin_read64, [:codebin_handle, :uint32], :uint64
45
+ attach_function :codeBin_read32, [:codebin_handle, :uint32], :uint32
46
+ attach_function :codeBin_read16, [:codebin_handle, :uint32], :uint16
47
+ attach_function :codeBin_read8, [:codebin_handle, :uint32], :uint8
48
+ attach_function :codeBin_readCString, [:codebin_handle, :uint32], :string
49
+ attach_function :codeBin_getSize, [:codebin_handle], :uint32
50
+ attach_function :codeBin_getStartAddress, [:codebin_handle], :uint32
51
+
52
+ attach_function :armBin_alloc, [], :codebin_handle
53
+ attach_function :armBin_release, [:codebin_handle], :void
54
+ attach_function :armBin_load, [:codebin_handle, :string, :uint32, :uint32, :uint32, :bool], :bool
55
+ attach_function :armBin_getEntryPointAddress, [:codebin_handle], :uint32
56
+ attach_function :armBin_getModuleParams, [:codebin_handle], :module_params_handle
57
+ attach_function :armBin_sanityCheckAddress, [:codebin_handle, :uint32], :bool
58
+
59
+ attach_function :overlayBin_alloc, [], :codebin_handle
60
+ attach_function :overlayBin_release, [:codebin_handle], :void
61
+ attach_function :overlayBin_load, [:codebin_handle, :string, :uint32, :bool, :int32], :bool
62
+
63
+ end
64
+
65
+
66
+ module Nitro
67
+ extend NitroBind
68
+
69
+ class OvtEntry < FFI::Struct
70
+ layout :overlay_id, :uint32,
71
+ :ram_address, :uint32,
72
+ :ram_size, :uint32,
73
+ :bss_size, :uint32,
74
+ :sinit_start, :uint32,
75
+ :sinit_end, :uint32,
76
+ :file_id, :uint32,
77
+ :comp_field, :uint32
78
+
79
+ def id
80
+ self[:overlay_id]
81
+ end
82
+
83
+ def ram_addr
84
+ self[:ram_address]
85
+ end
86
+
87
+ def sinit_bounds
88
+ self[:sinit_start]..self[:sinit_end]
89
+ end
90
+
91
+ def fid
92
+ self[:file_id]
93
+ end
94
+
95
+ def compressed_size
96
+ (self[:comp_field] >> 8) & 0xffffff # 24 bits
97
+ end
98
+
99
+ def is_compressed?
100
+ (self[:comp_field] & 0xff) == 1 # 8 bits
101
+ end
102
+ alias_method :compressed?, :is_compressed?
103
+
104
+ end
105
+
106
+ class OvtBin
107
+ include NitroBind
108
+
109
+ attr_reader :size, :entry_count
110
+
111
+ def initialize(args = {})
112
+ if args.has_key? :file_path
113
+ bin = File.binread(args[:file_path])
114
+ @size = bin.bytesize
115
+ @ptr = FFI::MemoryPointer.new(:uint8, @size)
116
+ @ptr.put_bytes(0, bin)
117
+
118
+ elsif args.has_key?(:ptr) && args.has_key?(:size)
119
+ @ptr = args[:ptr]
120
+ @size = args[:size]
121
+ @entry_count = @size / OvtEntry.size
122
+ else
123
+ raise ArgumentError
124
+ end
125
+ end
126
+
127
+ def get_entry(id)
128
+ raise IndexError if id > @entry_count-1
129
+ OvtEntry.new(@ptr + id*OvtEntry.size)
130
+ end
131
+
132
+ end
133
+
134
+ class CodeBin
135
+ include NitroBind
136
+
137
+ def read64(addr)
138
+ codeBin_read64(@ptr, addr)
139
+ end
140
+ alias_method :read_dword, :read64
141
+
142
+ def read32(addr)
143
+ codeBin_read32(@ptr, addr)
144
+ end
145
+ alias_method :read_word, :read32
146
+
147
+ def read16(addr)
148
+ codeBin_read16(@ptr, addr)
149
+ end
150
+ alias_method :read_hword, :read16
151
+
152
+ def read8(addr)
153
+ codeBin_read8(@ptr, addr)
154
+ end
155
+ alias_method :read_byte, :read8
156
+
157
+ def size
158
+ codeBin_getSize(@ptr)
159
+ end
160
+
161
+ def start_address
162
+ codeBin_getStartAddress(@ptr)
163
+ end
164
+ alias_method :start_addr, :start_address
165
+
166
+ def end_address
167
+ start_address + size
168
+ end
169
+ alias_method :end_addr, :end_address
170
+
171
+ def bounds
172
+ start_addr..end_addr
173
+ end
174
+
175
+ def read(range = bounds, step = 4)
176
+ raise ArgumentError, 'step must be 1, 2, 4, or 8 (bytes)' unless [1,2,4,8].include? step
177
+ raise ArgumentError, 'range must be a Range' unless range.is_a? Range
178
+
179
+ clamped = Range.new([range.begin || start_addr, start_addr].max, [range.end || end_addr, end_addr].min)
180
+
181
+ clamped.step(step).map { |addr| [send(:"read#{step * 8}", addr), addr] }
182
+ end
183
+
184
+ def each_word(range = bounds)
185
+ read(range).each do |word, addr|
186
+ yield word, addr
187
+ end
188
+ end
189
+
190
+ def each_dword(range = bounds)
191
+ read(range,8).each do |dword, addr|
192
+ yield dword, addr
193
+ end
194
+ end
195
+
196
+ def each_hword(range = bounds)
197
+ read(range,2).each do |hword, addr|
198
+ yield hword, addr
199
+ end
200
+ end
201
+
202
+ def each_byte(range = bounds)
203
+ read(range,1).each do |byte, addr|
204
+ yield byte, addr
205
+ end
206
+ end
207
+
208
+ def each_char(range = bounds)
209
+ each_byte(range) do |char, addr|
210
+ yield char.chr, addr
211
+ end
212
+ end
213
+
214
+ def read_cstring(start_addr)
215
+ codeBin_readCString(@ptr, start_addr)
216
+ end
217
+ alias_method :read_cstr, :read_cstring
218
+
219
+ end
220
+
221
+ class ArmBin < CodeBin
222
+ include NitroBind
223
+
224
+ attr_reader :module_params
225
+
226
+ class ModuleParams < FFI::Struct
227
+ layout :autoload_list_start, :uint32,
228
+ :autoload_list_end, :uint32,
229
+ :autoload_start, :uint32,
230
+ :static_bss_start, :uint32,
231
+ :static_bss_end, :uint32,
232
+ :comp_static_end, :uint32,
233
+ :sdk_version_id, :uint32,
234
+ :nitro_code_be, :uint32,
235
+ :nitro_code_le, :uint32
236
+ end
237
+
238
+ def initialize(args = {})
239
+ if args.has_key? :file_path
240
+ @ptr = FFI::AutoPointer.new(armBin_alloc, method(:armBin_release))
241
+ if not File.exist? args[:file_path]
242
+ puts "Error: #{args[:file_path]} does not exist"
243
+ raise 'ArmBin initialization failed'
244
+ end
245
+ armBin_load(@ptr, args[:file_path], args[:entry_addr], args[:ram_addr], args[:auto_load_hook_offset],
246
+ args[:is_arm9] || true)
247
+
248
+ elsif args.has_key?(:ptr) && args[:ptr].is_a?(FFI::AutoPointer)
249
+ @ptr = args[:ptr]
250
+
251
+ else
252
+ raise ArgumentError, 'ArmBin must be initialized with a file or a pointer'
253
+ end
254
+
255
+ @module_params = ModuleParams.new(armBin_getModuleParams(@ptr))
256
+ end
257
+
258
+ def entry_point_address
259
+ armBin_getEntryPointAddress(@ptr)
260
+ end
261
+ alias_method :entry_addr, :entry_point_address
262
+ alias_method :entry_point_addr, :entry_point_address
263
+
264
+ def sane_address?(addr)
265
+ armBin_sanityCheckAddress(@ptr, addr)
266
+ end
267
+ alias_method :sane_addr?, :sane_address?
268
+
269
+ end
270
+
271
+ class OverlayBin < CodeBin
272
+ include NitroBind
273
+
274
+ attr_reader :id
275
+
276
+ def initialize(id, args = {})
277
+ @id = id
278
+ if [:file_path, :ram_addr, :is_compressed].all? { |k| args.key?(k) }
279
+ @ptr = FFI::AutoPointer.new(overlayBin_alloc, method(:overlayBin_release))
280
+ if !File.exist? args[:file_path]
281
+ puts "Error: #{args[:file_path]} does not exist"
282
+ raise "OverlayBin initialization failed"
283
+ end
284
+ overlayBin_load(@ptr, args[:file_path], args[:ram_addr], args[:is_compressed], @id)
285
+
286
+ elsif args.has_key?(:ptr) && args[:ptr].is_a?(FFI::AutoPointer)
287
+ @ptr = args[:ptr]
288
+
289
+ else
290
+ raise ArgumentError, 'OverlayBin must be initialized with a file or a pointer'
291
+ end
292
+ end
293
+
294
+ end
295
+
296
+ class HeaderBin
297
+ include NitroBind
298
+
299
+ def initialize(arg)
300
+ if arg.is_a? String
301
+ @ptr = FFI::AutoPointer.new(headerBin_alloc, method(:headerBin_release))
302
+ if not File.exist? arg
303
+ puts "Error: #{arg} does not exist"
304
+ raise "HeaderBin initialization failed"
305
+ end
306
+ headerBin_load(@ptr, arg)
307
+ elsif arg.is_a? FFI::Pointer
308
+ @ptr = arg
309
+ end
310
+ end
311
+
312
+ def game_title
313
+ headerBin_getGameTitle(@ptr)
314
+ end
315
+
316
+ def game_code
317
+ headerBin_getGameCode(@ptr)
318
+ end
319
+
320
+ def maker_code
321
+ headerBin_getMakerCode(@ptr)
322
+ end
323
+
324
+ def arm9_auto_load_hook_offset
325
+ headerBin_getArm9AutoLoadHookOffset(@ptr)
326
+ end
327
+ alias_method :arm9_auto_load_hook_ofs, :arm9_auto_load_hook_offset
328
+
329
+ def arm7_auto_load_hook_offset
330
+ headerBin_getArm7AutoLoadHookOffset(@ptr)
331
+ end
332
+ alias_method :arm7_auto_load_hook_ofs, :arm7_auto_load_hook_offset
333
+
334
+ def arm9_entry_address
335
+ headerBin_getArm9EntryAddress(@ptr)
336
+ end
337
+ alias_method :arm9_entry_addr, :arm9_entry_address
338
+
339
+ def arm7_entry_address
340
+ headerBin_getArm7EntryAddress(@ptr)
341
+ end
342
+ alias_method :arm7_entry_addr, :arm7_entry_address
343
+
344
+ def arm9_ram_address
345
+ headerBin_getArm9RamAddress(@ptr)
346
+ end
347
+ alias_method :arm9_ram_addr, :arm9_ram_address
348
+
349
+ def arm7_ram_address
350
+ headerBin_getArm7RamAddress(@ptr)
351
+ end
352
+ alias_method :arm7_ram_addr, :arm7_ram_address
353
+
354
+ def arm9_ovt_size
355
+ headerBin_getArm9OvTSize(@ptr)
356
+ end
357
+
358
+ end
359
+
360
+ class Rom
361
+ include NitroBind
362
+
363
+ attr_reader :header, :arm9, :arm7, :overlays, :overlay_count, :overlay_table
364
+
365
+ alias_method :ov_count, :overlay_count
366
+ alias_method :ov_table, :overlay_table
367
+ alias_method :ovt, :overlay_table
368
+
369
+ def initialize(file_path)
370
+ @ptr = FFI::AutoPointer.new(nitroRom_alloc, method(:nitroRom_release))
371
+
372
+ # Check whether file exists here because if C++ throws an exception we get a segfault
373
+ if !File.exist?(file_path)
374
+ puts "Error: #{file_path} does not exist"
375
+ raise "Rom initialization failed"
376
+ end
377
+
378
+ nitroRom_load(@ptr, file_path)
379
+ @header = HeaderBin.new(nitroRom_getHeader(@ptr))
380
+ @arm9 = ArmBin.new(ptr: FFI::AutoPointer.new(nitroRom_loadArm9(@ptr), method(:armBin_release)))
381
+ @arm7 = ArmBin.new(ptr: FFI::AutoPointer.new(nitroRom_loadArm7(@ptr), method(:armBin_release)))
382
+ @overlay_count = nitroRom_getOverlayCount(@ptr)
383
+ @overlays = Array.new(@overlay_count)
384
+ @overlay_table = OvtBin.new(ptr: nitroRom_getArm9OvT(@ptr), size: @header.arm9_ovt_size)
385
+ define_ov_accessors
386
+ end
387
+
388
+ def size
389
+ nitroRom_getSize(@ptr)
390
+ end
391
+
392
+ def get_file(id)
393
+ nitroRom_getFile(id)
394
+ end
395
+
396
+ def get_file_size(id)
397
+ nitroRom_getFileSize(id)
398
+ end
399
+
400
+ def nitro_sdk_version
401
+ @arm9.module_params[:sdk_version_id]
402
+ end
403
+
404
+ def load_overlay(id)
405
+ raise IndexError if id > @overlay_count-1
406
+ ov_ptr = nitroRom_loadOverlay(@ptr, id)
407
+ raise "Failed to load overlay #{id}." if !ov_ptr
408
+ @overlays[id] = OverlayBin.new(id, ptr: FFI::AutoPointer.new(ov_ptr, method(:overlayBin_release)))
409
+ end
410
+ alias_method :load_ov, :load_overlay
411
+
412
+ def get_overlay(id)
413
+ raise IndexError if id > @overlay_count-1
414
+ load_overlay(id) if @overlays[id].nil?
415
+ @overlays[id]
416
+ end
417
+ alias_method :get_ov, :get_overlay
418
+
419
+ def each_overlay
420
+ @overlay_count.times do |i|
421
+ yield get_overlay(i), i
422
+ end
423
+ end
424
+ alias_method :each_ov, :each_overlay
425
+
426
+ private
427
+ def define_ov_accessors
428
+ (0..@overlay_count-1).each do |id|
429
+ self.class.define_method(:"overlay#{id}") do
430
+ get_overlay(id)
431
+ end
432
+ self.class.define_method(:"ov#{id}") do
433
+ get_overlay(id)
434
+ end
435
+ end
436
+ end
437
+
438
+ end
439
+
440
+ end
Binary file