npgrt 0.0.3 → 0.0.4

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.
@@ -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