Class: Python::Pickle::Protocol4

Inherits:
Protocol3 show all
Defined in:
lib/python/pickle/protocol4.rb

Overview

Implements Python Pickle protocol 4.

Direct Known Subclasses

Protocol5

Constant Summary collapse

OPCODES =

Opcodes for Pickle protocol 4.

Instance Attribute Summary

Attributes inherited from Protocol

#io

Instance Method Summary collapse

Methods inherited from Protocol2

#read_int_le, #read_uint16_le, #unpack_int_le

Methods inherited from Protocol1

#read_float64_be, #read_uint32_le, #read_uint8

Methods inherited from Protocol0

#read_escaped_char, #read_float, #read_hex_escaped_char, #read_int, #read_long, #read_nl_string, #read_string, #read_unicode_escaped_char, #read_unicode_escaped_char16, #read_unicode_escaped_char32, #read_unicode_string

Methods inherited from Protocol

#read

Constructor Details

#initialize(io) ⇒ Protocol4

Initializes the protocol 4 reader/writer.



23
24
25
26
27
# File 'lib/python/pickle/protocol4.rb', line 23

def initialize(io)
  super(io)

  @io_stack = []
end

Instance Method Details

#enter_frame(frame) ⇒ Object

Enters a new data frame.

Parameters:

  • frame (String)

    The contents of the data frame.



271
272
273
274
# File 'lib/python/pickle/protocol4.rb', line 271

def enter_frame(frame)
  @io_stack.push(@io)
  @io = StringIO.new(frame)
end

#leave_frameObject

Leaves a data frame and restores Python::Pickle::Protocol#io.



279
280
281
# File 'lib/python/pickle/protocol4.rb', line 279

def leave_frame
  @io = @io_stack.pop
end

#read_frame(length) ⇒ String

Reads a data frame of the given length.

Parameters:

  • length (Integer)

    The desired length of the frame.

Returns:

  • (String)

    The read data frame.



261
262
263
# File 'lib/python/pickle/protocol4.rb', line 261

def read_frame(length)
  @io.read(length)
end

#read_instructionInstruction

Reads an instruction from the pickle stream.

Returns:

Raises:



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/python/pickle/protocol4.rb', line 54

def read_instruction
  case (opcode = @io.getbyte)
  #
  # Protocol 0 instructions
  #
  when 40 # MARK
    Instructions::MARK
  when 46 # STOP
    Instructions::STOP
  when 48 # POP
    Instructions::POP
  when 49 # POP_MARK
    Instructions::POP_MARK
  when 50 # DUP
    Instructions::DUP
  when 70 # FLOAT
    Instructions::Float.new(read_float)
  when 73 # INT
    Instructions::Int.new(read_int)
  when 76 # LONG
    Instructions::Long.new(read_long)
  when 78 # NONE
    Instructions::NONE
  when 82 # REDUCE
    Instructions::REDUCE
  when 83 # STRING
    Instructions::String.new(read_string)
  when 86 # UNICODE
    Instructions::String.new(read_unicode_string)
  when 97 # APPEND
    Instructions::APPEND
  when 98 # BUILD
    Instructions::BUILD
  when 99 # GLOBAL
    Instructions::Global.new(read_nl_string,read_nl_string)
  when 100 # DICT
    Instructions::DICT
  when 103 # GET
    Instructions::Get.new(read_int)
  when 108 # LIST
    Instructions::LIST
  when 112 # PUT
    Instructions::Put.new(read_int)
  when 115 # SETITEM
    Instructions::SETITEM
  when 116 # TUPLE
    Instructions::TUPLE
  #
  # Protocol 1 instructions
  #
  when 41  # EMPTY_TUPLE
    Instructions::EMPTY_TUPLE
  when 71  # BINFLOAT
    Instructions::BinFloat.new(read_float64_be)
  when 75  # BININT1
    Instructions::BinInt1.new(read_uint8)
  when 84  # BINSTRING
    length = read_uint32_le
    string = @io.read(length)

    Instructions::BinString.new(length,string)
  when 85  # SHORT_BINSTRING
    length = read_uint8
    string = @io.read(length)

    Instructions::ShortBinString.new(length,string)
  when 88  # BINUNICODE
    length = read_uint32_le
    string = @io.read(length).force_encoding(Encoding::UTF_8)

    Instructions::BinUnicode.new(length,string)
  when 93  # EMPTY_LIST
    Instructions::EMPTY_LIST
  when 101 # APPENDS
    Instructions::APPENDS
  when 104 # BINGET
    Instructions::BinGet.new(read_uint8)
  when 106 # LONG_BINGET
    Instructions::LongBinGet.new(read_uint32_le)
  when 113 # BINPUT
    Instructions::BinPut.new(read_uint8)
  when 117 # SETITEMS
    Instructions::SETITEMS
  when 125 # EMPTY_DICT
    Instructions::EMPTY_DICT
  #
  # Protocol 2 instructions
  #
  when 128 # PROT
    Instructions::Proto.new(read_uint8)
  when 129 # NEWOBJ
    Instructions::NEWOBJ
  when 130 # EXT1
    Instructions::Ext1.new(read_uint8)
  when 131 # EXT2
    Instructions::Ext2.new(read_uint16_le)
  when 132 # EXT4
    Instructions::Ext4.new(read_uint32_le)
  when 133 # TUPLE1
    Instructions::TUPLE1
  when 134 # TUPLE2
    Instructions::TUPLE2
  when 135 # TUPLE3
    Instructions::TUPLE3
  when 136 # NEWTRUE
    Instructions::NEWTRUE
  when 137 # NEWFALSE
    Instructions::NEWFALSE
  when 138 # LONG1
    length = read_uint8
    long   = read_int_le(length)

    Instructions::Long1.new(length,long)
  when 139 # LONG4
    length = read_uint32_le
    long   = read_int_le(length)

    Instructions::Long4.new(length,long)
  #
  # Protocol 3 instructions
  #
  when 66 # BINBYTES
    length = read_uint32_le
    bytes  = @io.read(length)

    Instructions::BinBytes.new(length,bytes)
  when 67 # SHORT_BINBYTES
    length = read_uint8
    bytes  = @io.read(length)

    Instructions::ShortBinBytes.new(length,bytes)
  #
  # Protocol 4 instructions
  #
  when 140 # SHORT_BINUNICODE
    length = read_uint8
    string = read_utf8_string(length)

    Instructions::ShortBinUnicode.new(length,string)
  when 141 # BINUNICODE8
    length = read_uint64_le
    string = read_utf8_string(length)

    Instructions::BinUnicode8.new(length,string)
  when 142 # BINBYTES8
    length = read_uint64_le
    bytes  = @io.read(length)

    Instructions::BinBytes8.new(length,bytes)
  when 143 # EMPTY_SET
    Instructions::EMPTY_SET
  when 144 # ADDITEMS
    Instructions::ADDITEMS
  when 145 # FROZENSET
    Instructions::FROZENSET
  when 146 # NEWOBJ_EX
    Instructions::NEWOBJ_EX
  when 147 # STACK_GLOBAL
    Instructions::STACK_GLOBAL
  when 148 # MEMOIZE
    Instructions::MEMOIZE
  when 149 # FRAME
    length = read_uint64_le

    enter_frame(read_frame(length))

    Instructions::Frame.new(length)
  else
    raise(InvalidFormat,"invalid opcode (#{opcode.inspect}) for protocol 4")
  end
ensure
  if @io.eof? && !@io_stack.empty?
    leave_frame
  end
end

#read_uint64_leInteger

Reads an unsigned 64bit integer, in little-endian byte-order.

Returns:

  • (Integer)


235
236
237
# File 'lib/python/pickle/protocol4.rb', line 235

def read_uint64_le
  @io.read(8).unpack1('Q<')
end

#read_utf8_string(length) ⇒ String

Reads a UTF-8 string of the desired length.

Parameters:

  • length (Integer)

    The desired length to read.

Returns:

  • (String)

    The read UTF-8 string.



248
249
250
# File 'lib/python/pickle/protocol4.rb', line 248

def read_utf8_string(length)
  @io.read(length).force_encoding(Encoding::UTF_8)
end