npgrt 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,8 +6,31 @@ module NPGRT
6
6
  super a
7
7
  end
8
8
 
9
- alias primitive_require require
9
+ ADDPATH = []
10
+
11
+ def binary_forms(a)
12
+ w = NPGRT::PlatformWidth.to_s
13
+ [ a, a+".dll", a+".so",
14
+ File.basename(a) + "_" + w + File.extname(a),
15
+ File.basename(a) + "_" + w + ".dll",
16
+ File.basename(a) + "_" + w + ".so"
17
+ ]
18
+ end
10
19
 
20
+ def require_binary(a)
21
+ path = binary_forms(a).inject([]){|ret, v|
22
+ ret.concat Gem.find_files v
23
+ }
24
+ v = path.map{|x|
25
+ FileTest.file?(x) ? NPGRT.normalize_pathsep_os(File.dirname(x)) : nil
26
+ }.compact - ADDPATH
27
+ ENV['path'] += ";" + v.join(";")
28
+ ADDPATH.concat v
29
+ end
30
+
31
+ alias primitive_require require
32
+ private :primitive_require
33
+
11
34
  def require(a)
12
35
  primitive_require(a) do |x|
13
36
  try_build x
data/lib/npgrt/version.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  module NPGRT
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
+ PlatformWidth = [nil].pack("p").size * 8
4
+ PtrType = PlatformWidth == 32 ? "L" : "Q"
3
5
  end
@@ -1,3 +1,5 @@
1
1
  module NPGRT
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.3"
3
+ PlatformWidth = [nil].pack("p").size * 8
4
+ PtrType = PlatformWidth == 32 ? "L" : "Q"
3
5
  end
@@ -1,16 +1,32 @@
1
1
  module NPGRT
2
2
  require 'Win32API' unless defined? ::Win32API
3
3
  module Win32API
4
+
4
5
  W = ::Win32API
5
6
  class API
6
7
  def initialize(dll, func, param = nil, ret = "L")
7
- @dll, @func, @param, @ret = dll, func, param, ret
8
-
8
+ @dll, @func, @param, @ret = dll, func, param, ret
9
+ end
10
+
11
+ def findapi(dll, func, param, ret)
12
+ [dll, File.basename(dll) + "_" + NPGRT::PlatformWidth.to_s + File.extname(dll)].each{|d|
13
+ [func, func + "A", func + "W"].each{|f|
14
+ if (a = begin
15
+ W.new(d, f, param, ret)
16
+ rescue LoadError, RuntimeError
17
+ nil
18
+ end
19
+ )
20
+ return a
21
+ end
22
+ }
23
+ }
24
+ raise Errno::ENOENT, " NPGRT::API: Can't find a proper DLL for #{dll}!#{func}"
9
25
  end
10
26
 
11
27
  def call(*args)
12
28
  param = @param || guess(args)
13
- @api ||= W.new(@dll, @func, param, @ret)
29
+ @api ||= findapi(@dll, @func, param, @ret)
14
30
  @api.call(*args)
15
31
  end
16
32
 
@@ -27,13 +43,16 @@ module NPGRT
27
43
  API.new dll, func, params, ret
28
44
  end
29
45
 
46
+ def checked_api(dll, func, params = nil, ret = "L", info = "Error!", exclass = RuntimeError)
47
+ lambda{|*a| raise exclass, info if 0 != API.new(dll, func, params, ret).call(*a)}
48
+ end
30
49
  def addressof(dll, func)
31
50
  dl = api('kernel32', 'GetModuleHandle').call(dll)
32
51
  dl = (dl == 0) ? dl : api('kernel32', 'LoadLibrary').call(dll)
33
52
  api('kernel32', 'GetProcAddress').call dl, func
34
53
  end
35
54
 
36
- def memwrite(addr, buf, len = buf.size)
55
+ def memwrite(addr, buf, len = buf.length)
37
56
  api('Kernel32', 'RtlMoveMemory').call addr, buf, len
38
57
  end
39
58
 
@@ -52,13 +71,13 @@ module NPGRT
52
71
  memread(grant_all(addr, size), size)
53
72
  end
54
73
 
55
- def memwrite!(addr, buf, len = buf.size)
56
- memread(grant_all(addr, len), buf, len)
74
+ def memwrite!(addr, buf, len = buf.length)
75
+ memwrite(grant_all(addr, len), buf, len)
57
76
  end
58
77
 
59
78
  CP_UTF8 = {cp: 65001, suffix:"\0", encoding: "utf-8"}
60
- CP_ANSI = {cp: 0, suffix:"\0", encoding: "ascii-8bit"}
61
- CP_OEM = CP_ANSI
79
+ CP_ANSI = {cp: 0, suffix:"\0", encoding: "us-ascii"}
80
+ CP_ACP = CP_OEM = CP_ANSI
62
81
  CP_GBK = {cp: 65001, suffix: "\0", encoding: "gbk"}
63
82
 
64
83
  def to_unicode(string, codepage = CP_UTF8)
@@ -72,14 +91,13 @@ module NPGRT
72
91
  len = api('Kernel32', 'WideCharToMultiByte').call codepage[:cp], 0, string, -1, 0, 0, 0, 0
73
92
  buf = "\0"*len
74
93
  api('Kernel32', 'WideCharToMultiByte').call codepage[:cp], 0, string, -1, buf, len, 0, 0
75
- b = buf[0..-1].sub(/\0+$/){}
76
- if b.respond_to?(:force_encoding)
77
- b.force_encoding(defined?($RGSS_SCRIPTS) ?
94
+ if buf.respond_to?(:force_encoding)
95
+ buf.force_encoding(defined?($RGSS_SCRIPTS) ?
78
96
  'utf-8' :
79
97
  codepage[:encoding])
80
98
  else
81
- b
82
- end
99
+ buf
100
+ end[0..-1].sub(/\0+$/){}
83
101
  end
84
102
 
85
103
  def strread(addr)
@@ -92,13 +110,314 @@ module NPGRT
92
110
  to_codepage(memread(addr, len*2+2))
93
111
  end
94
112
 
95
-
113
+ INI_VALUE_MAX = 2048
114
+ def iniread(app, key, ini = "Game.ini")
115
+ buf = "\0\0"*INI_VALUE_MAX
116
+ ini = normalize_pathsep_os ini
117
+ app, key, ini = [app, key, ini].map{|x| to_unicode(x + "\0\0")+"\0\0"}
118
+ len = api('kernel32', 'GetPrivateProfileStringW').call(app, key, "", buf, INI_VALUE_MAX, ini)
119
+ to_codepage buf
120
+ end
96
121
 
122
+ def iniwrite(app, key, value, ini = "Game.ini")
123
+ ini = normalize_pathsep_os ini
124
+ app, key, value, ini = [app, key, value, ini].map{|x| to_unicode(x + "\0\0")+"\0\0"}
125
+ api('kernel32', 'WritePrivateProfileStringW').call(
126
+ app, key, value, ini
127
+ )
128
+ end
97
129
 
98
130
 
131
+ module REG
132
+ HKEY_CLASSES_ROOT,
133
+ HKEY_CURRENT_USER,
134
+ HKEY_LOCAL_MACHINE,
135
+ HKEY_USERS,
136
+ HKEY_PERFORMANCE_DATA,
137
+ HKEY_CURRENT_CONFIG,
138
+ HKEY_DYN_DATA = *(0x80000000..0x80000010)
139
+
140
+ HKCR = HKEY_CLASSES_ROOT
141
+ HKCU = HKEY_CURRENT_USER
142
+ HKLM = HKEY_LOCAL_MACHINE
143
+
144
+ REG_NONE = 0
145
+ REG_SZ = 1
146
+ REG_EXPAND_SZ = 2
147
+ REG_BINARY = 3
148
+ REG_DWORD = 4
149
+ REG_DWORD_BIG_ENDIAN = 5
150
+ REG_MULTI_SZ = 7
151
+
152
+
153
+ ESUCCESS = 0
154
+ EMOREDATA = 234
155
+ BYTEINC = 4096
156
+ end
157
+
158
+ def regopenkey(path, valuename)
159
+ path =~ /([^\\]*)\\(.*)/
160
+ whole, main, child = *$~
161
+ main = REG.const_get(main)
162
+ key = [0].pack(NPGRT::PtrType)
163
+ child = to_unicode(child + "\0\0")+"\0\0"
164
+ valuename = case valuename
165
+ when 0, nil
166
+ 0
167
+ else
168
+ to_unicode(valuename+"\0\0")+"\0\0"
169
+ end
170
+ checked_api(
171
+ 'advapi32', 'RegOpenKeyW', nil, 'L', "Open Key #{path} Error!"
172
+ ).call(
173
+ main, child, key
174
+ )
175
+ key = key.unpack(NPGRT::PtrType).first
176
+ [key, valuename]
177
+ end
178
+
179
+ def regclosekey(key)
180
+ api('advapi32', 'RegCloseKey').call key
181
+ end
182
+ def regread(path, valuename = 0, type = :REG_SZ)
183
+ type = REG.const_get(type) if Symbol === type
184
+ key, valuename = regopenkey(path, valuename)
185
+ len = REG::BYTEINC
186
+ plen = [len].pack(NPGRT::PtrType)
187
+ buf = "\0\0"*len
188
+ ptype = [type].pack(NPGRT::PtrType)
189
+ ret = api('advapi32', 'RegQueryValueExW').call(key, valuename, 0, ptype, buf, plen)
190
+ while ret == REG::EMOREDATA
191
+ len += REG::BYTEINC
192
+ plen = [len].pack(NPGRT::PtrType)
193
+ buf = "\0\0"*len
194
+ ret = api('advapi32', 'RegQueryValueExW').call(key, valuename, 0, ptype, buf, plen)
195
+
196
+ end
197
+ if ret == REG::ESUCCESS
198
+ return buf[0, plen.unpack(NPGRT::PtrType).first*2]
199
+ else
200
+ raise "Query Key #{path} failed"
201
+ end
202
+ ensure
203
+ regclosekey key
204
+ end
205
+
206
+ def regstrread(type, valuename = "")
207
+ val = regread(type, valuename)
208
+ to_codepage val + "\0\0"
209
+ end
210
+
211
+ def regwrite(path, valuename = nil, value = "", type = :REG_SZ)
212
+ key, valuename = regopenkey(path, valuename)
213
+ type = REG.const_get(type) if Symbol === type
214
+ raise "RegWrite #{path} Error!" if 0 != api('advapi32', 'RegSetValueExW').call(
215
+ key,
216
+ valuename,
217
+ 0,
218
+ type,
219
+ value,
220
+ value.length
221
+ )
222
+ return true
223
+ ensure
224
+ regclosekey key
225
+ end
226
+
227
+ def regstrwrite(path, valuename = nil, value = "")
228
+ regwrite(path, valuename, to_unicode(value+"\0\0")+"\0\0", :REG_SZ)
229
+ end
230
+
231
+ extend self
232
+ Win32File = Struct.new(:read, :write, :close, :flush)
233
+ ReadFile = api('kernel32', 'ReadFile')
234
+ WriteFile = api('kernel32', 'WriteFile')
235
+ CloseFile = api('Kernel32', 'CloseHandle')
236
+ TYPE_VOIDP = NPGRT::PtrType
237
+ OS64 = TYPE_VOIDP == "Q"
238
+ PTRLEN = OS64 ? 8 : 4
239
+
240
+ def hfileread(handle, len)
241
+ buf = "\0"*len
242
+ llen = [0].pack(TYPE_VOIDP)
243
+ ret = ReadFile.call(handle, buf, len, llen, 0)
244
+ outlen = llen.unpack(TYPE_VOIDP).first
245
+ ret != 0 ? buf[0, outlen] : nil
246
+ end
247
+
248
+ def hfilewrite(handle, buf, len = buf.to_str.length)
249
+ llen = [0].pack(TYPE_VOIDP)
250
+ ret = WriteFile.call(handle, buf.to_str, len, llen, 0)
251
+ outlen = llen.unpack(TYPE_VOIDP).first
252
+ ret != 0 ? outlen : nil
253
+ end
254
+
255
+ def hfilereada(handle, len)
256
+ ret = hfileread(handle, len)
257
+ !ret ? ret : to_codepage(to_unicode(ret+"\0\0", CP_ACP)+"\0\0")
258
+ end
259
+
260
+ def hfilereadw(handle, len)
261
+ ret = hfileread(handle, len)
262
+ !ret ? ret : to_codepage(ret+"\0\0")
263
+ end
264
+
265
+
266
+ STARTUPINFOTYPE = {
267
+ :sizeof => OS64 ? 104 : 68,
268
+ :show => OS64 ? 64 : 48,
269
+ :handles => OS64 ? [80, 88, 96] : [56, 60, 64]
270
+ }
271
+
272
+ CreatePipe = api('Kernel32', 'CreatePipe')
273
+ def winpipe
274
+ buf = "\0"*(PTRLEN*2)
275
+ sa = [8+PTRLEN, nil, 1].pack(TYPE_VOIDP + "p" + TYPE_VOIDP)
276
+ addr = [buf].pack("p").unpack(TYPE_VOIDP).first
277
+ CreatePipe.call addr, addr+PTRLEN, sa, 1
278
+ ret = buf.unpack(TYPE_VOIDP*2)
279
+ {:in => ret[0], :out => ret[1]}
280
+ end
281
+ def open3(path, dir = nil, env = nil)
282
+ si = "\0"*STARTUPINFOTYPE[:sizeof]
283
+ api('Kernel32', 'GetStartupInfoW').call si
284
+ si[STARTUPINFOTYPE[:show], 2] = [0].pack("S")
285
+ stdin, stdout, stderr = winpipe, winpipe, winpipe
286
+ si[STARTUPINFOTYPE[:handles][0], PTRLEN] = [stdin[:in]].pack(TYPE_VOIDP)
287
+ si[STARTUPINFOTYPE[:handles][1], PTRLEN] = [stdout[:out]].pack(TYPE_VOIDP)
288
+ si[STARTUPINFOTYPE[:handles][2], PTRLEN] = [stderr[:out]].pack(TYPE_VOIDP)
289
+ pi = "\0"*PTRLEN*4
290
+ path = to_unicode(path + "\0\0")+"\0\0"
291
+ dir = dir == nil ? nil : to_unicode(dir + "\0\0")+"\0\0"
292
+ env = env == nil ? nil : to_unicode(env + "\0\0")+"\0\0"
293
+ api('Kernel32', 'CreateProcessW').call(
294
+ 0,
295
+ path,
296
+ 0,
297
+ 0,
298
+ 1,
299
+ 0,
300
+ 0,
301
+ dir,
302
+ si,
303
+ pi,
304
+ )
305
+ CloseFile.call(stdin[:in])
306
+ CloseFile.call(stdout[:out])
307
+ CloseFile.call(stderr[:out])
308
+ u = pi.unpack(TYPE_VOIDP*4)
309
+ proc_info = Hash[ [:process, :thread, :pid, :tid].zip(u) ]
310
+ CloseFile.call(proc_info[:process])
311
+ CloseFile.call(proc_info[:thread])
312
+ ret = yield stdin[:out], stdout[:in], stderr[:in], proc_info
313
+ api('Kernel32', 'TerminateProcess').call proc_info[:process], ret
314
+ end
315
+
316
+ def popen(path, dir = nil, env = nil)
317
+ open3 path, dir, env do |a, b, c, d|
318
+ yield a,b
319
+ end
320
+ end
321
+
322
+ CloseSocket = api('ws2_32', 'closesocket')
323
+ OpenSocket = api('ws2_32', 'socket')
324
+ Connect = api('ws2_32', 'connect')
325
+ Send = api('ws2_32', 'send')
326
+ Recv = api('ws2_32', 'recv')
327
+ def udpnew(addr = nil)
328
+ addr = sockaddr(*addr) if Array === addr
329
+ so = OpenSocket.call 2, 2, 0
330
+ Connect.call so, addr, addr.size if addr
331
+ so
332
+ end
333
+
334
+ def tcpnew(addr = nil)
335
+ addr = sockaddr(*addr) if Array === addr
336
+ so = OpenSocket.call 2, 1, 6
337
+ Connect.call so, addr, addr.size if addr
338
+ so
339
+ end
340
+
341
+ def sockaddr(host, port)
342
+ [2, port, *host].pack("snCCCCx8")
343
+ end
344
+
345
+ def udpclose(u)
346
+ CloseSocket.call u
347
+ end
348
+
349
+ def tcpclose(u)
350
+ CloseSocket.call u
351
+ end
352
+
353
+ def socketwrite(h, buf)
354
+ Send.call h, buf, buf.length, 0
355
+ end
356
+
357
+ def socketread(h, size)
358
+ buf = "\0" * size
359
+ ret = Recv.call h, buf, size, 0
360
+ case ret
361
+ when -1, 0
362
+ nil
363
+ else
364
+ buf[0, ret]
365
+ end
366
+ end
99
367
 
100
-
368
+
369
+ def simplehttpread(addr, hostname = addr[/http:\/\/([^\/]*)/, 1],
370
+ resource = addr[/http:\/\/([^\/]*)(.*)$/, 2])
371
+ request = "GET #{resource} HTTP/1.1\r\n"\
372
+ "host:#{hostname}\r\n"\
373
+ "\r\n\r\n\r\n\r\n"
374
+ t = tcpnew
375
+ if hostname[0][/[0-9]/]
376
+ u = addr = api('ws2_32', 'inet_addr').call(
377
+ to_codepage(to_unicode(hostname+"\0\0")+"\0", CP_ANSI)+"\0"
378
+ )
379
+ else
380
+ hostent = api('ws2_32', 'gethostbyname').call(
381
+ to_codepage(to_unicode(hostname+"\0\0")+"\0", CP_ANSI)+"\0"
382
+ )
383
+
384
+ addr = memread(hostent+PTRLEN*3, PTRLEN)
385
+ addr = addr.unpack(TYPE_VOIDP).first
386
+ addr = memread(addr, PTRLEN)
387
+ addr = addr.unpack(TYPE_VOIDP).first
388
+ addr = memread(addr, PTRLEN)
389
+ u = addr.unpack("L").first
390
+ end
391
+ uaddr = [2, 0, 0, 80, u].pack("CCCCLx8")
392
+
393
+ raise "Can't connect to Server " if -1 == Connect.call(t, uaddr, 16)
394
+ socketwrite t, request
395
+ responseheader = ""
396
+ while v = socketread(t, 20480)
397
+ responseheader << v
398
+ if pos = responseheader.index("\r\n\r\n")
399
+ responsebody = responseheader[pos+4..-1]
400
+ responseheader = responseheader[0...pos]
401
+ break
402
+ end
403
+ yield responseheader, nil if block_given?
404
+ end
405
+
406
+ if !(length = responseheader[/Content-length:\s*(\d+)/i, 1])
407
+ length = 1e100
408
+ else
409
+ length = length.to_i
410
+ end
411
+
412
+ while responsebody.length < length && (v = socketread(t, 20480))
413
+ responsebody << v
414
+ yield responseheader, responsebody if block_given?
415
+ end
416
+ tcpclose t
417
+ true
418
+ end
419
+
420
+
101
421
  end
102
422
 
103
- extend Win32API
104
423
  end