gap50 0.1.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.
@@ -0,0 +1,40 @@
1
+ module Gap
2
+ class DLLFunction
3
+ def initialize(path, name)
4
+ @path = path
5
+ @name = name
6
+ end
7
+
8
+ def call(*args)
9
+ param = args.map do |x|
10
+ case x
11
+ when Integer
12
+ "L"
13
+ else
14
+ "p"
15
+ end
16
+ end
17
+ begin
18
+ Win32API.new(@path, @name, param, "L").call(*args)
19
+ rescue LoadError
20
+ Win32API.new(File.expand_path(@path), @name, param, "L").call(*args)
21
+ end
22
+ end
23
+ end
24
+
25
+ class DLL
26
+ def initialize(filename, sam = Gap::Main, &block)
27
+ @sam = sam
28
+ @filename = filename
29
+ @realpath = @sam.genfile(@filename, &block).tr("/", "\\")
30
+ end
31
+
32
+ def [](name)
33
+ DLLFunction.new @realpath, name
34
+ end
35
+
36
+ def method_missing(sym, *args)
37
+ self[sym.to_s].call(*args)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ module Gap
2
+ class Exec
3
+ def initialize(sam = Gap::Main)
4
+ @sam = sam
5
+ end
6
+
7
+ def exec(cmdline, input)
8
+ md5 = MD5.hexdigest(cmdline) + MD5.hexdigest(input)
9
+ inputfile = _file md5, ".input"
10
+ outputfile = _file md5, ".output"
11
+ outf = md5 + ".output"
12
+ key = [Samsara::Meta.new(:Exec), outf]
13
+ @sam.gen key do
14
+ @sam.writefile inputfile, input
15
+ system "#{cmdline} < #{inputfile} > #{outputfile}"
16
+ @sam.readfile outputfile
17
+ end
18
+ end
19
+
20
+ def marshal(cmdline, input)
21
+ Marshal.load exec(cmdline, input)
22
+ end
23
+
24
+ DEFAULT_EXEC = Exec.new
25
+ def self.exec(*a)
26
+ DEFAULT_EXEC.exec(*a)
27
+ end
28
+
29
+ def self.marshal(*a)
30
+ DEFAULT_EXEC.marshal(*a)
31
+ end
32
+
33
+ private
34
+ def _file(name, ext = "")
35
+ "temp/exec_" << name << ext
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module Gap
2
+ Main = Samsara.new "main.sam"
3
+ end
@@ -0,0 +1,96 @@
1
+ module Gap
2
+ class Require
3
+ def initialize(sam = Gap::Main, strict = true)
4
+ @strict = strict
5
+ @sam = sam
6
+ end
7
+
8
+ def require(*args)
9
+ if @strict
10
+ args.each{|x|
11
+ _require_strict x
12
+ }
13
+ else
14
+ args.each{|x|
15
+ _require x
16
+ }
17
+ end
18
+ ensure
19
+ $@.replace caller if $@
20
+ end
21
+
22
+ ORIGIN = Kernel.method(:require)
23
+ INSTANCE_ORIGIN = Kernel.instance_method(:require)
24
+ DEFAULT_REQUIRE = Require.new
25
+ REQUIRE_STACK = [[INSTANCE_ORIGIN, Kernel]]
26
+
27
+
28
+ def replace_kernel!
29
+ that = self
30
+ REQUIRE_STACK.push [self.class.instance_method(:require), self]
31
+ _fix_kernel
32
+ ensure
33
+ $@.replace caller if $@
34
+ end
35
+
36
+ def back_require!
37
+ REQUIRE_STACK.pop
38
+ _fix_kernel
39
+ ensure
40
+ $@.replace caller if $@
41
+ end
42
+
43
+ def use_kernel!
44
+ Kernel.send :define_method, INSTANCE_ORIGIN
45
+ ensure
46
+ $@.replace caller if $@
47
+ end
48
+
49
+ private
50
+ def _require(a)
51
+ ORIGIN.call a
52
+ rescue
53
+ if ex.to_s =~ /^LoadError: .*? -- (.*)$/
54
+ file = $1
55
+ path = "./" + @sam.genfile(file)
56
+ ORIGIN.call path
57
+ else
58
+ raise ArgumentError, "Can't load #{a}"
59
+ end
60
+ end
61
+
62
+ def _require_strict(file)
63
+ [file, file + ".rb"].each{|x|
64
+ begin
65
+ if @sam.has_file_in?(x)
66
+ path = "./" + @sam.genfile(x)
67
+ return ORIGIN.call path
68
+ end
69
+ rescue LoadError
70
+ ensure
71
+ $@.replace caller if $@
72
+ end
73
+ }
74
+ ORIGIN.call file
75
+ ensure
76
+ $@.replace caller if $@
77
+ end
78
+
79
+ def _fix_kernel
80
+ if REQUIRE_STACK[-1]
81
+ m, o = REQUIRE_STACK[-1]
82
+ if o == Kernel
83
+ use_kernel!
84
+ else
85
+ Kernel.send :define_method, :require do |*args|
86
+ m.bind(o).call(*args)
87
+ end
88
+ end
89
+ else
90
+ use_kernel!
91
+ end
92
+ ensure
93
+ $@.replace caller if $@
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,9 @@
1
+ require "gap50/version"
2
+ require 'gap50/preload'
3
+ require 'gap50/cache'
4
+ require 'gap50/samsara'
5
+ require 'gap50/gap'
6
+ require 'gap50/ext'
7
+ module Gap50
8
+ # Your code goes here...
9
+ end
@@ -0,0 +1,12 @@
1
+ begin
2
+ Win32API
3
+ rescue NameError
4
+ require 'win32api'
5
+ end
6
+
7
+ begin
8
+ Zlib
9
+ rescue NameError
10
+ require 'zlib'
11
+ end
12
+
@@ -0,0 +1,4 @@
1
+ require 'gap50/samsara/md5.rb'
2
+ require 'gap50/samsara/random.rb'
3
+ require 'gap50/samsara/maker.rb'
4
+ require 'gap50/samsara/samsara.rb'
@@ -0,0 +1,113 @@
1
+ module Gap
2
+ class Maker
3
+ RND = Random.new
4
+ attr_accessor :temp, :sam
5
+
6
+
7
+ def initialize(sam = nil, temp = genname, &block)
8
+ @sam = sam
9
+ @temp = temp
10
+ if defined? instance_exec
11
+ transaction do |m|
12
+ instance_exec &block
13
+ end
14
+ else
15
+ transaction do |m|
16
+ instance_eval &block
17
+ end
18
+ end
19
+ end
20
+
21
+ def path(name)
22
+ @temp + "/" + name
23
+ end
24
+
25
+ def readfile(name)
26
+ @sam.readfile path(name)
27
+ end
28
+
29
+ def writefile(name, value)
30
+ @sam.writefile path(name), value
31
+ end
32
+
33
+ def copyfile(src, dest)
34
+ writefile dest, @sam.readfile(src)
35
+ end
36
+
37
+ def exec(cmd)
38
+ system "cd #{@temp} && #{cmd}"
39
+ end
40
+
41
+ def transaction
42
+ _create
43
+ ret = yield self
44
+ _import_all
45
+ _cleanup
46
+ ret
47
+ end
48
+
49
+ def asBase64
50
+ _import_all
51
+ @sam.toBase64
52
+ end
53
+
54
+ def asMarshal
55
+ _import_all
56
+ @sam.toMarshal
57
+ end
58
+
59
+ def genlib(name, text)
60
+ writefile "cpp/#{name}.cpp", %{#define GAPI(type) extern "C" type __stdcall
61
+ #{text}
62
+ }
63
+ exec "g++ cpp/#{name}.cpp -o cpp/#{name}.dll -static -s -shared -m32 -Wl,-add-stdcall-alias"
64
+ end
65
+
66
+ def from(name)
67
+ @sam = Samsara.new name
68
+ _export_all
69
+ end
70
+
71
+ alias COPY copyfile
72
+ alias WRITE writefile
73
+ alias READ readfile
74
+ alias RUN exec
75
+ alias FROM from
76
+ alias CXX genlib
77
+ private
78
+ def _export_all
79
+ @sam.each{|k, v|
80
+ if k[0] == Samsara::MetaFile
81
+ @sam.export k[1], @temp
82
+ end
83
+ }
84
+ end
85
+
86
+ def _import_all
87
+ len = @temp.length + 1
88
+ Dir.glob(@temp + "/**/*") do |f|
89
+ next if FileTest.directory?(f)
90
+ name = f[len..-1]
91
+ @sam.import name, @temp
92
+ end
93
+ end
94
+
95
+ def _cleanup
96
+ @sam.rmdir_p(@temp)
97
+ end
98
+
99
+ def _create
100
+ if !FileTest.directory?(temp)
101
+ Dir.mkdir temp
102
+ end
103
+ end
104
+
105
+ def genname
106
+ while 0
107
+ name = "temp-#{RND.hex(16)}"
108
+ return name if !FileTest.exists?(name)
109
+ end
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,44 @@
1
+ module Gap
2
+ MD5_INIT = Win32API.new("ADVAPI32", "MD5Init", "p", "L")
3
+ MD5_UPDATE = Win32API.new("ADVAPI32", "MD5Update", "ppL", "L")
4
+ MD5_FINAL = Win32API.new("ADVAPI32", "MD5Final", "p", "L")
5
+ class MD5
6
+ def initialize
7
+ @ctx = "\0" * 128 # buf
8
+ MD5_INIT.call(@ctx)
9
+ end
10
+
11
+ def update(str)
12
+ MD5_UPDATE.call(@ctx, str, str.unpack("C*").size)
13
+ end
14
+
15
+ def digest
16
+ MD5_FINAL.call(@ctx)
17
+ @ctx[88, 16]
18
+ end
19
+
20
+ def self.digest(a)
21
+ x = MD5.new
22
+ x.update a
23
+ x.digest
24
+ end
25
+
26
+ def self.hexdigest(a)
27
+ digest(a).unpack("H*").first
28
+ end
29
+
30
+ def self.file(fn)
31
+ open(fn, 'rb') do |f|
32
+ x = MD5.new
33
+ while (r = f.read(10240))
34
+ x.update(r)
35
+ end
36
+ x.digest
37
+ end
38
+ end
39
+
40
+ def self.filehex(fn)
41
+ file(fn).unpack("H*").first
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ module Gap
2
+ CR_ACQUIRE = Win32API.new("ADVAPI32", "CryptAcquireContext", "pLLLL", "L")
3
+ CR_GENRANDOM = Win32API.new("ADVAPI32", "CryptGenRandom", "LLp", "L")
4
+ CR_RELEASE = Win32API.new("ADVAPI32", "CryptReleaseContext", "LL", "L")
5
+ class Random
6
+ REG = {}
7
+ def self.auto_release_proc
8
+ proc{|id|
9
+ if REG.include? id
10
+ _dispose REG[id]
11
+ REG.delete id
12
+ end
13
+ }
14
+ end
15
+
16
+ def self.register_auto_release(id, ptr)
17
+ REG[object_id] = ptr
18
+ ObjectSpace.define_finalizer self, auto_release_proc
19
+ end
20
+
21
+ def initialize
22
+ buf = "\0" * 4
23
+ CR_ACQUIRE.call buf, 0, 0, 1, -268435456
24
+ @ptr, = buf.unpack("L")
25
+ self.class.register_auto_release object_id, @ptr
26
+ end
27
+
28
+ def bytes(len = 16)
29
+ buf = "\0" * len
30
+ CR_GENRANDOM.call @ptr, len, buf
31
+ buf
32
+ end
33
+
34
+ def hex(len = 16)
35
+ bytes(len).unpack("H*").first
36
+ end
37
+
38
+ def next_int
39
+ bytes(4).unpack("L").first
40
+ end
41
+
42
+ def self._dispose(ptr)
43
+ if ptr
44
+ CR_RELEASE.call ptr, 0
45
+ end
46
+ end
47
+
48
+ def dispose
49
+ self.class._dispose @ptr
50
+ @ptr = nil
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,195 @@
1
+ module Gap
2
+ class Samsara
3
+ Meta = Struct.new :meta
4
+ MetaFile = Meta.new :file
5
+ MetaMD5 = Meta.new :filemd5
6
+ attr_accessor :filepath
7
+ def initialize(name, filepath = "samfile")
8
+ @cache = Gap::Cache.new name
9
+ @filepath = filepath
10
+ end
11
+
12
+ def fromBase64(b64)
13
+ @cache.fromBase64 b64
14
+ end
15
+
16
+ def toBase64
17
+ @cache.toBase64
18
+ end
19
+
20
+ def fromMarshal(text)
21
+ @cache.fromMarshal text
22
+ end
23
+
24
+ def toMarshal
25
+ @cache.toMarshal
26
+ end
27
+
28
+ def each(&block)
29
+ @cache.each(&block)
30
+ end
31
+
32
+ def export(file, dir)
33
+ _export file, dir
34
+ end
35
+
36
+ def import(file, dir)
37
+ _import file, dir
38
+ end
39
+ #
40
+ # gen : [Any] -> ([Any] -> Any) -> Any
41
+ #
42
+ def gen(*path)
43
+ if @cache.has?(path)
44
+ @cache[path]
45
+ else
46
+ @cache.transaction do |db|
47
+ db[path] = yield path
48
+ db[path]
49
+ end
50
+ end
51
+ end
52
+
53
+ #
54
+ # genfile : filename -> [Any] -> (filename -> [Any] -> Any) -> Any
55
+ #
56
+ def genfile(filename, args = nil, &block)
57
+ realpath = file(filename)
58
+ md5key = [MetaMD5, filename]
59
+ filekey = [MetaFile, filename]
60
+ if @cache.has?(md5key) &&
61
+ @cache.has?(filekey) &&
62
+ FileTest.file?(realpath) &&
63
+ MD5.filehex(realpath) == @cache[md5key]
64
+ elsif @cache.has?(filekey)
65
+ _writefile realpath, @cache[filekey]
66
+ else
67
+ u = yield filekey
68
+ @cache.transaction do |db|
69
+ db[md5key] = MD5.hexdigest u
70
+ db[filekey] = u
71
+ _writefile realpath, @cache[filekey]
72
+ end
73
+ end
74
+ realpath
75
+ end
76
+
77
+ def has_file_in?(filename)
78
+ md5key = [MetaMD5, filename]
79
+ filekey = [MetaFile, filename]
80
+ @cache.has?(md5key) &&
81
+ @cache.has?(filekey) &&
82
+ @cache[md5key] != nil &&
83
+ MD5.hexdigest(@cache[filekey]) == @cache[md5key]
84
+ end
85
+
86
+ def need_update_file?(filename, realfile)
87
+ if has_file_in?(filename)
88
+ md5key = [MetaMD5, filename]
89
+ MD5.filehex(realfile) != @cache[md5key]
90
+ else
91
+ true
92
+ end
93
+ end
94
+
95
+ def file(name)
96
+ _file(name)
97
+ end
98
+
99
+ def writefile(a, b)
100
+ _writefile a, b
101
+ end
102
+
103
+ def readfile(a)
104
+ _readfile a
105
+ end
106
+
107
+ def mangle(name)
108
+ _mangle(name)
109
+ end
110
+
111
+ def rmdir_p(name)
112
+ _rmdir_p(name)
113
+ end
114
+
115
+
116
+ private
117
+ def _file(name)
118
+ File.join(@filepath, _mangle(name))
119
+ end
120
+
121
+ def _mangle(name)
122
+ name.gsub("://", "$SEP$/").gsub(/[:"']/){ "$#{$&.unpack("H")}$" }
123
+ end
124
+
125
+ def _demangle(name)
126
+ name.gsub("$SEP$/", "://").gsub(/\$([a-f0-9]+)\$/) { [$1].pack("H") }
127
+ end
128
+
129
+ def _mkdirp(name)
130
+ names = name.tr("\\", "/").split("/")[0..-2]
131
+ names.inject(""){|a, b|
132
+ if a == ""
133
+ path = b
134
+ else
135
+ path = a + "/" + b
136
+ end
137
+ if !FileTest.directory?(path)
138
+ Dir.mkdir(path)
139
+ end
140
+ path
141
+ }
142
+ end
143
+
144
+ def _readfile(name)
145
+ open(name, 'rb') do |f|
146
+ f.read
147
+ end
148
+ end
149
+ def _writefile(name, val)
150
+ _mkdirp(name)
151
+ open(name, "wb") do |f|
152
+ f.write val
153
+ end
154
+ end
155
+
156
+ def _export(file, dir)
157
+ if has_file_in?(file)
158
+ name = _mangle(dir + "/" + file)
159
+ filekey = [MetaFile, file]
160
+ _writefile(name, @cache[filekey])
161
+ else
162
+ raise "File not found #{file}"
163
+ end
164
+ end
165
+
166
+ def _import(file, dir)
167
+ name = _mangle(dir + "/" + file)
168
+ @cache.transaction do |db|
169
+ filekey = [MetaFile, file]
170
+ md5key = [MetaMD5, file]
171
+ db.remove filekey
172
+ db.remove md5key
173
+ content = _readfile name
174
+ db[md5key] = MD5.hexdigest(content)
175
+ db[filekey] = content
176
+ end
177
+ end
178
+
179
+ def _rmdir_p(name)
180
+ raise if name == nil || name[0] == "/"
181
+ files = [name]
182
+ Dir.glob(name + "/**/*") do |f|
183
+ files << f
184
+ end
185
+ files.sort!{|a, b| b.length <=> a.length}
186
+ files.each{|x|
187
+ if FileTest.file?(x)
188
+ File.delete x
189
+ else
190
+ Dir.delete x
191
+ end
192
+ }
193
+ end
194
+ end
195
+ end