rmarshal 0.1

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,2 @@
1
+ require 'rmarshal/unmarshal'
2
+ require 'rmarshal/pyc'
@@ -0,0 +1,56 @@
1
+ require 'rmarshal/opcodes'
2
+
3
+ class Disasm
4
+ def initialize(code, consts, varnames, names)
5
+ @code = code
6
+ @consts = consts
7
+ @varnames = varnames
8
+ @names = names
9
+ @insts = []
10
+ @off = 0
11
+
12
+ while @off != @code.size
13
+ @insts[@insts.size] = parse
14
+ end
15
+ end
16
+
17
+ def insts() @insts end
18
+ def byte()
19
+ val = @code[@off].ord
20
+ @off += 1
21
+ val
22
+ end
23
+ def short()
24
+ val = @code[@off...@off+2].unpack('s')[0]
25
+ @off += 2
26
+ val
27
+ end
28
+
29
+ def parse
30
+ off = @off
31
+ opcd = byte
32
+ if not $opcodes.has_key? opcd
33
+ raise "Unknown opcode #{opcd}"
34
+ end
35
+
36
+ name, arg = $opcodes[opcd]
37
+ if arg == nil
38
+ [off, name]
39
+ else
40
+ val = short
41
+ arg = case arg
42
+ when :const then @consts[val]
43
+ when :name then @names[val]
44
+ when :jrel then @off + val
45
+ when :local then @varnames[val]
46
+ else val
47
+ end
48
+
49
+ [off, name, arg]
50
+ end
51
+ end
52
+ end
53
+
54
+ def disasm(*args)
55
+ Disasm.new(*args).insts
56
+ end
@@ -0,0 +1,115 @@
1
+ $opcodes = {
2
+ 0x00 => [:STOP_CODE, nil],
3
+ 0x01 => [:POP_TOP, nil],
4
+ 0x02 => [:ROT_TWO, nil],
5
+ 0x03 => [:ROT_THREE, nil],
6
+ 0x04 => [:DUP_TOP, nil],
7
+ 0x05 => [:ROT_FOUR, nil],
8
+ 0x09 => [:NOP, nil],
9
+ 0x0A => [:UNARY_POSITIVE, nil],
10
+ 0x0B => [:UNARY_NEGATIVE, nil],
11
+ 0x0C => [:UNARY_NOT, nil],
12
+ 0x0D => [:UNARY_CONVERT, nil],
13
+ 0x0F => [:UNARY_INVERT, nil],
14
+ 0x12 => [:LIST_APPEND, nil],
15
+ 0x13 => [:BINARY_POWER, nil],
16
+ 0x14 => [:BINARY_MULTIPLY, nil],
17
+ 0x15 => [:BINARY_DIVIDE, nil],
18
+ 0x16 => [:BINARY_MODULO, nil],
19
+ 0x17 => [:BINARY_ADD, nil],
20
+ 0x18 => [:BINARY_SUBTRACT, nil],
21
+ 0x19 => [:BINARY_SUBSCR, nil],
22
+ 0x1A => [:BINARY_FLOOR_DIVIDE, nil],
23
+ 0x1B => [:BINARY_TRUE_DIVIDE, nil],
24
+ 0x1C => [:INPLACE_FLOOR_DIVIDE, nil],
25
+ 0x1D => [:INPLACE_TRUE_DIVIDE, nil],
26
+ 0x1E => [:SLICE_0, nil],
27
+ 0x1F => [:SLICE_1, nil],
28
+ 0x20 => [:SLICE_2, nil],
29
+ 0x21 => [:SLICE_3, nil],
30
+ 0x28 => [:STORE_SLICE_0, nil],
31
+ 0x29 => [:STORE_SLICE_1, nil],
32
+ 0x2A => [:STORE_SLICE_2, nil],
33
+ 0x2B => [:STORE_SLICE_3, nil],
34
+ 0x32 => [:DELETE_SLICE_0, nil],
35
+ 0x33 => [:DELETE_SLICE_1, nil],
36
+ 0x34 => [:DELETE_SLICE_2, nil],
37
+ 0x35 => [:DELETE_SLICE_3, nil],
38
+ 0x36 => [:STORE_MAP, nil],
39
+ 0x37 => [:INPLACE_ADD, nil],
40
+ 0x38 => [:INPLACE_SUBTRACT, nil],
41
+ 0x39 => [:INPLACE_MULTIPLY, nil],
42
+ 0x3A => [:INPLACE_DIVIDE, nil],
43
+ 0x3B => [:INPLACE_MODULO, nil],
44
+ 0x3C => [:STORE_SUBSCR, nil],
45
+ 0x3D => [:DELETE_SUBSCR, nil],
46
+ 0x3E => [:BINARY_LSHIFT, nil],
47
+ 0x3F => [:BINARY_RSHIFT, nil],
48
+ 0x40 => [:BINARY_AND, nil],
49
+ 0x41 => [:BINARY_XOR, nil],
50
+ 0x42 => [:BINARY_OR, nil],
51
+ 0x43 => [:INPLACE_POWER, nil],
52
+ 0x44 => [:GET_ITER, nil],
53
+ 0x46 => [:PRINT_EXPR, nil],
54
+ 0x47 => [:PRINT_ITEM, nil],
55
+ 0x48 => [:PRINT_NEWLINE, nil],
56
+ 0x49 => [:PRINT_ITEM_TO, nil],
57
+ 0x4A => [:PRINT_NEWLINE_TO, nil],
58
+ 0x4B => [:INPLACE_LSHIFT, nil],
59
+ 0x4C => [:INPLACE_RSHIFT, nil],
60
+ 0x4D => [:INPLACE_AND, nil],
61
+ 0x4E => [:INPLACE_XOR, nil],
62
+ 0x4F => [:INPLACE_OR, nil],
63
+ 0x50 => [:BREAK_LOOP, nil],
64
+ 0x51 => [:WITH_CLEANUP, nil],
65
+ 0x52 => [:LOAD_LOCALS, nil],
66
+ 0x53 => [:RETURN_VALUE, nil],
67
+ 0x54 => [:IMPORT_STAR, nil],
68
+ 0x55 => [:EXEC_STMT, nil],
69
+ 0x56 => [:YIELD_VALUE, nil],
70
+ 0x57 => [:POP_BLOCK, nil],
71
+ 0x58 => [:END_FINALLY, nil],
72
+ 0x59 => [:BUILD_CLASS, nil],
73
+ 0x5A => [:STORE_NAME, :name],
74
+ 0x5B => [:DELETE_NAME, :name],
75
+ 0x5C => [:UNPACK_SEQUENCE, nil],
76
+ 0x5D => [:FOR_ITER, :jrel],
77
+ 0x5F => [:STORE_ATTR, :name],
78
+ 0x60 => [:DELETE_ATTR, :name],
79
+ 0x61 => [:STORE_GLOBAL, :name],
80
+ 0x62 => [:DELETE_GLOBAL, :name],
81
+ 0x63 => [:DUP_TOPX, nil],
82
+ 0x64 => [:LOAD_CONST, :const],
83
+ 0x65 => [:LOAD_NAME, :name],
84
+ 0x66 => [:BUILD_TUPLE, nil],
85
+ 0x67 => [:BUILD_LIST, nil],
86
+ 0x68 => [:BUILD_MAP, nil],
87
+ 0x69 => [:LOAD_ATTR, :name],
88
+ 0x6A => [:COMPARE_OP, :compare],
89
+ 0x6B => [:IMPORT_NAME, :name],
90
+ 0x6C => [:IMPORT_FROM, :name],
91
+ 0x6E => [:JUMP_FORWARD, :jrel],
92
+ 0x6F => [:JUMP_IF_FALSE, :jrel],
93
+ 0x70 => [:JUMP_IF_TRUE, :jrel],
94
+ 0x71 => [:JUMP_ABSOLUTE, :jabs],
95
+ 0x74 => [:LOAD_GLOBAL, :name],
96
+ 0x77 => [:CONTINUE_LOOP, :jabs],
97
+ 0x78 => [:SETUP_LOOP, :jrel],
98
+ 0x79 => [:SETUP_EXCEPT, :jrel],
99
+ 0x7A => [:SETUP_FINALLY, :jrel],
100
+ 0x7C => [:LOAD_FAST, :local],
101
+ 0x7D => [:STORE_FAST, :local],
102
+ 0x7E => [:DELETE_FAST, :local],
103
+ 0x82 => [:RAISE_VARARGS, nil],
104
+ 0x83 => [:CALL_FUNCTION, nil],
105
+ 0x84 => [:MAKE_FUNCTION, nil],
106
+ 0x85 => [:BUILD_SLICE, nil],
107
+ 0x86 => [:MAKE_CLOSURE, nil],
108
+ 0x87 => [:LOAD_CLOSURE, :free],
109
+ 0x88 => [:LOAD_DEREF, :free],
110
+ 0x89 => [:STORE_DEREF, :free],
111
+ 0x8C => [:CALL_FUNCTION_VAR, nil],
112
+ 0x8D => [:CALL_FUNCTION_KW, nil],
113
+ 0x8E => [:CALL_FUNCTION_VAR_KW, nil],
114
+ 0x8F => [:EXTENDED_ARG, nil],
115
+ }
@@ -0,0 +1,9 @@
1
+ require 'rmarshal'
2
+
3
+ def pyc(fn)
4
+ fp = File.open fn
5
+
6
+ magic, timestamp = fp.read(8).unpack('ii')
7
+
8
+ unmarshal fp
9
+ end
@@ -0,0 +1,113 @@
1
+ require 'rmarshal/disasm'
2
+ require 'set'
3
+
4
+ class Code
5
+ def initialize(
6
+ argcount, nlocals, stacksize, flags, code, consts, names, varnames, freevars,
7
+ cellvars, filename, name, firstlineno, lnotab
8
+ )
9
+
10
+ @argcount, @nlocals, @stacksize, @flags = argcount, nlocals, stacksize, flags
11
+ @code, @consts, @names, @varnames = code, consts, names, varnames
12
+ @freevars, @cellvars, @filename, @name = freevars, cellvars, filename, name
13
+ @firstlineno, @lnotab = firstlineno, lnotab
14
+ end
15
+
16
+ def method_missing(sym)
17
+ instance_variable_get sym
18
+ end
19
+
20
+ def disassemble
21
+ disasm @code, @consts, @varnames, @names
22
+ end
23
+ end
24
+
25
+ class Unmarshal
26
+ def initialize(fp)
27
+ @fp = fp
28
+ @interned = []
29
+
30
+ @value = unmarshal
31
+ end
32
+
33
+ def value() @value end
34
+ def byte() @fp.read 1 end
35
+ def long() @fp.read(4).unpack('i')[0] end
36
+ def double() @fp.read(8).unpack('E')[0] end
37
+
38
+ def unmarshal
39
+ type = byte
40
+ case type
41
+ when '.' then :Ellipsis
42
+ when '0' then :null # Special!
43
+ when 'N' then nil
44
+ when 'T' then true
45
+ when 'F' then false
46
+
47
+ when 'c'
48
+ argcount, nlocals, stacksize, flags = long, long, long, long
49
+
50
+ code_, consts, names, varnames, freevars = unmarshal, unmarshal, unmarshal, unmarshal, unmarshal
51
+ cellvars, filename, name = unmarshal, unmarshal, unmarshal
52
+ firstlineno, lnotab = long, unmarshal
53
+
54
+ Code.new(
55
+ argcount, nlocals, stacksize, flags,
56
+ code_, consts, names, varnames, freevars,
57
+ cellvars, filename, name, firstlineno, lnotab
58
+ )
59
+
60
+ when 'f' then @fp.read(byte).to_f
61
+ when 'g' then double
62
+ when 'i' then long
63
+ when 'I' then @fp.read(8).unpack('q')[0]
64
+
65
+ when 'R'
66
+ @interned[long]
67
+
68
+ when 's' then @fp.read long
69
+
70
+ when 'S' then :StopIteration
71
+
72
+ when 't'
73
+ str = @fp.read long
74
+ @interned[@interned.size] = str
75
+ str
76
+
77
+ when 'u' then @fp.read(long).force_encoding 'utf-8'
78
+
79
+ when 'x'
80
+ Complex @fp.read(byte).to_f(), @fp.read(byte).to_f()
81
+ when 'y'
82
+ Complex double, double
83
+
84
+ when '(', '['
85
+ (0...long).map { unmarshal }
86
+
87
+ when '{'
88
+ val = {}
89
+
90
+ while true
91
+ key = unmarshal
92
+ break if key == :null
93
+
94
+ val[key] = unmarshal
95
+ end
96
+
97
+ val
98
+
99
+ when '<', '>'
100
+ Set.new((0...long).map { unmarshal })
101
+
102
+ when '?'
103
+ raise 'TYPE_UNKNOWN encountered. Incomplete marshal.'
104
+
105
+ else
106
+ raise "Unknown type '#{type}'"
107
+ end
108
+ end
109
+ end
110
+
111
+ def unmarshal(fp)
112
+ Unmarshal.new(fp).value
113
+ end
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Creates a file containing all possible marshal types
4
+
5
+ import marshal
6
+
7
+ def testfunc():
8
+ print 'Test'
9
+
10
+ def exhaustive():
11
+ return (
12
+ None, # TYPE_NONE 'N'
13
+ False, # TYPE_FALSE 'F'
14
+ True, # TYPE_TRUE 'T'
15
+ 0, # TYPE_INT 'i'
16
+ #1L, # TYPE_LONG 'l'
17
+ 0.0, # TYPE_BINARY_FLOAT 'g'
18
+ 1j, # TYPE_BINARY_COMPLEX 'y'
19
+ 'foo', # TYPE_STRING 's'
20
+ 'bar', # TYPE_INTERNED 't'
21
+ 'bar', # TYPE_STRINGREF 'R'
22
+ u'unicode €', # TYPE_UNICODE 'u'
23
+ [0, 'test', True], # TYPE_LIST '['
24
+ {0 : 1, 'bar' : 'baz'}, # TYPE_DICT '{'
25
+ testfunc.func_code, # TYPE_CODE 'c'
26
+
27
+ set([0, 1, 2]), # TYPE_SET
28
+ frozenset([3, 4, 5]), # TYPE_FROZENSET
29
+ StopIteration, # TYPE_STOPITER
30
+ Ellipsis, # TYPE_ELLIPSIS
31
+ )
32
+
33
+ marshal.dump(exhaustive(), file('tests\exhaustive.mrsh', 'wb'))
@@ -0,0 +1,5 @@
1
+ require 'rmarshal'
2
+ require 'pp'
3
+
4
+ fp = File.open 'exhaustive.mrsh'
5
+ pp unmarshal fp
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rmarshal
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Cody Brocious
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-20 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: cody.brocious@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/rmarshal/disasm.rb
26
+ - lib/rmarshal/opcodes.rb
27
+ - lib/rmarshal/pyc.rb
28
+ - lib/rmarshal/unmarshal.rb
29
+ - lib/rmarshal.rb
30
+ - test/exhaustive.py
31
+ - test/test.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/daeken/RMarshal
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Ruby gem to support the Python marshal format
60
+ test_files: []
61
+