blob: 41667e653783be3bf934ceba9a11afaaba373615 [file] [log] [blame]
José Fonseca299a1b32012-01-26 20:32:59 +00001/**************************************************************************
2 *
3 * Copyright 2012 Jose Fonseca
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26/*
27 * Python pickle writer
28 */
29
30#ifndef _PICKLE_HPP_
31#define _PICKLE_HPP_
32
33#include <assert.h>
34#include <stddef.h>
José Fonseca447576d2012-01-27 14:27:13 +000035#include <stdint.h>
José Fonseca299a1b32012-01-26 20:32:59 +000036
37#include <ostream>
38#include <string>
39
40
41class PickleWriter
42{
43private:
44 std::ostream &os;
45
46 /*
47 * Python pickle opcodes. See pickle.py and pickletools.py from Python
48 * standard library for details.
49 */
50 enum Opcode {
51 MARK = '(',
52 STOP = '.',
53 POP = '0',
54 POP_MARK = '1',
55 DUP = '2',
56 FLOAT = 'F',
57 INT = 'I',
58 BININT = 'J',
59 BININT1 = 'K',
60 LONG = 'L',
61 BININT2 = 'M',
62 NONE = 'N',
63 PERSID = 'P',
64 BINPERSID = 'Q',
65 REDUCE = 'R',
66 STRING = 'S',
67 BINSTRING = 'T',
68 SHORT_BINSTRING = 'U',
69 UNICODE = 'V',
70 BINUNICODE = 'X',
71 APPEND = 'a',
72 BUILD = 'b',
73 GLOBAL = 'c',
74 DICT = 'd',
75 EMPTY_DICT = '}',
76 APPENDS = 'e',
77 GET = 'g',
78 BINGET = 'h',
79 INST = 'i',
80 LONG_BINGET = 'j',
81 LIST = 'l',
82 EMPTY_LIST = ']',
83 OBJ = 'o',
84 PUT = 'p',
85 BINPUT = 'q',
86 LONG_BINPUT = 'r',
87 SETITEM = 's',
88 TUPLE = 't',
89 EMPTY_TUPLE = ')',
90 SETITEMS = 'u',
91 BINFLOAT = 'G',
92
José Fonseca447576d2012-01-27 14:27:13 +000093 PROTO = '\x80',
94 NEWOBJ = '\x81',
95 EXT1 = '\x82',
96 EXT2 = '\x83',
97 EXT4 = '\x84',
98 TUPLE1 = '\x85',
99 TUPLE2 = '\x86',
100 TUPLE3 = '\x87',
101 NEWTRUE = '\x88',
102 NEWFALSE = '\x89',
103 LONG1 = '\x8a',
104 LONG4 = '\x8b',
José Fonseca299a1b32012-01-26 20:32:59 +0000105 };
106
107public:
José Fonseca447576d2012-01-27 14:27:13 +0000108 PickleWriter(std::ostream &_os) :
José Fonsecab16a4a82012-03-16 08:21:29 +0000109 os(_os) {
110 }
111
112 inline void begin() {
José Fonseca299a1b32012-01-26 20:32:59 +0000113 os.put(PROTO);
114 os.put(2);
115 }
116
José Fonsecab16a4a82012-03-16 08:21:29 +0000117 inline void end() {
José Fonseca299a1b32012-01-26 20:32:59 +0000118 os.put(STOP);
119 }
120
121 inline void beginDict() {
122 os.put(EMPTY_DICT);
123 os.put(BINPUT);
124 os.put(1);
125 }
126
127 inline void endDict() {
128 }
129
130 inline void beginItem() {
131 }
132
133 inline void beginItem(const char * name) {
134 writeString(name);
135 }
136
137 inline void beginItem(const std::string &name) {
138 beginItem(name.c_str());
139 }
140
141 inline void endItem(void) {
142 os.put(SETITEM);
143 }
144
145 inline void beginList() {
146 os.put(EMPTY_LIST);
147 os.put(BINPUT);
148 os.put(1);
149 os.put(MARK);
150 }
151
152 inline void endList(void) {
153 os.put(APPENDS);
154 }
155
156 inline void beginTuple() {
157 os.put(MARK);
158 }
159
160 inline void endTuple(void) {
161 os.put(TUPLE);
162 }
163
José Fonseca299a1b32012-01-26 20:32:59 +0000164 inline void writeString(const char *s, size_t length) {
165 if (!s) {
166 writeNone();
167 return;
168 }
169
170 if (length < 256) {
171 os.put(SHORT_BINSTRING);
172 os.put(length);
173 } else {
174 os.put(BINSTRING);
José Fonseca447576d2012-01-27 14:27:13 +0000175 putInt32(length);
José Fonseca299a1b32012-01-26 20:32:59 +0000176 }
177 os.write(s, length);
178
179 os.put(BINPUT);
180 os.put(1);
181 }
182
183 inline void writeString(const char *s) {
184 if (!s) {
185 writeNone();
186 return;
187 }
188
189 writeString(s, strlen(s));
190 }
191
192 inline void writeString(const std::string &s) {
193 writeString(s.c_str(), s.size());
194 }
195
196 inline void writeNone(void) {
197 os.put(NONE);
198 }
199
200 inline void writeBool(bool b) {
201 os.put(b ? NEWTRUE : NEWFALSE);
202 }
203
José Fonseca447576d2012-01-27 14:27:13 +0000204 inline void writeInt(uint8_t i) {
205 os.put(BININT1);
206 os.put(i);
José Fonseca299a1b32012-01-26 20:32:59 +0000207 }
208
José Fonseca447576d2012-01-27 14:27:13 +0000209 inline void writeInt(uint16_t i) {
210 if (i < 0x100) {
211 writeInt((uint8_t)i);
212 } else {
213 os.put(BININT2);
214 putInt16(i);
215 }
216 }
217
218 inline void writeInt(int32_t i) {
219 if (0 <= i && i < 0x10000) {
220 writeInt((uint16_t)i);
221 } else {
222 os.put(BININT);
223 putInt32(i);
224 }
225 }
226
227 inline void writeInt(uint32_t i) {
228 if (i < 0x8000000) {
229 writeInt((int32_t)i);
230 } else {
231 writeLong(i);
232 }
233 }
234
235 inline void writeInt(long long i) {
236 if (-0x8000000 <= i && i < 0x8000000) {
237 writeInt((int32_t)i);
238 } else {
239 writeLong(i);
240 }
241 }
242
243 inline void writeInt(unsigned long long i) {
244 if (i < 0x8000000) {
245 writeInt((int32_t)i);
246 } else {
247 writeLong(i);
248 }
249 }
250
251 inline void writeFloat(double f) {
252 union {
253 double f;
254 char c[8];
255 } u;
256
257 assert(sizeof u.f == sizeof u.c);
258 u.f = f;
259
260 os.put(BINFLOAT);
261 os.put(u.c[7]);
262 os.put(u.c[6]);
263 os.put(u.c[5]);
264 os.put(u.c[4]);
265 os.put(u.c[3]);
266 os.put(u.c[2]);
267 os.put(u.c[1]);
268 os.put(u.c[0]);
269 }
270
José Fonsecaeba2dec2012-03-17 16:12:22 +0000271 inline void writeByteArray(const void *buf, size_t length) {
272 os.put(GLOBAL);
273 os << "__builtin__\nbytearray\n";
274 os.put(BINPUT);
275 os.put(1);
276 writeString(static_cast<const char *>(buf), length);
277 os.put(TUPLE1);
278 os.put(REDUCE);
279 }
280
José Fonseca447576d2012-01-27 14:27:13 +0000281protected:
282 inline void putInt16(uint16_t i) {
283 os.put( i & 0xff);
284 os.put( i >> 8 );
285 }
286
287 inline void putInt32(uint32_t i) {
288 os.put( i & 0xff);
289 os.put((i >> 8) & 0xff);
290 os.put((i >> 16) & 0xff);
291 os.put( i >> 24 );
292 }
293
294 template< class T >
295 inline void writeLong(T l) {
296 os.put(LONG1);
297
298 if (l == 0) {
299 os.put(0);
300 return;
301 }
302
José Fonseca447576d2012-01-27 14:27:13 +0000303 // Same as l >> (8 * sizeof l), but without the warnings
304 T sign = l < 0 ? ~0 : 0;
José Fonsecad64e5b22012-10-05 20:55:28 +0100305
306 T sl = l;
307 unsigned c = 0;
308 do {
José Fonseca447576d2012-01-27 14:27:13 +0000309 ++c;
José Fonsecad64e5b22012-10-05 20:55:28 +0100310 } while (sl >>= 8 != sign);
311
José Fonseca447576d2012-01-27 14:27:13 +0000312 // Add an extra byte if sign bit doesn't match
313 if (((l >> (8 * c - 1)) & 1) != ((l >> (8 * sizeof l - 1)) & 1)) {
314 ++c;
315 }
316 os.put(c);
317
318 for (unsigned i = 0; i < c; ++ i) {
319 os.put(l & 0xff);
320 l >>= 8;
321 }
José Fonseca299a1b32012-01-26 20:32:59 +0000322 }
323};
324
325#endif /* _Pickle_HPP_ */