blob: f333960a7adefb31a57d48165c2da5ac753bdb6e [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é Fonseca299a1b32012-01-26 20:32:59 +0000109 os(_os)
110 {
111 os.put(PROTO);
112 os.put(2);
113 }
114
115 ~PickleWriter() {
116 os.put(STOP);
117 }
118
119 inline void beginDict() {
120 os.put(EMPTY_DICT);
121 os.put(BINPUT);
122 os.put(1);
123 }
124
125 inline void endDict() {
126 }
127
128 inline void beginItem() {
129 }
130
131 inline void beginItem(const char * name) {
132 writeString(name);
133 }
134
135 inline void beginItem(const std::string &name) {
136 beginItem(name.c_str());
137 }
138
139 inline void endItem(void) {
140 os.put(SETITEM);
141 }
142
143 inline void beginList() {
144 os.put(EMPTY_LIST);
145 os.put(BINPUT);
146 os.put(1);
147 os.put(MARK);
148 }
149
150 inline void endList(void) {
151 os.put(APPENDS);
152 }
153
154 inline void beginTuple() {
155 os.put(MARK);
156 }
157
158 inline void endTuple(void) {
159 os.put(TUPLE);
160 }
161
José Fonseca299a1b32012-01-26 20:32:59 +0000162 inline void writeString(const char *s, size_t length) {
163 if (!s) {
164 writeNone();
165 return;
166 }
167
168 if (length < 256) {
169 os.put(SHORT_BINSTRING);
170 os.put(length);
171 } else {
172 os.put(BINSTRING);
José Fonseca447576d2012-01-27 14:27:13 +0000173 putInt32(length);
José Fonseca299a1b32012-01-26 20:32:59 +0000174 }
175 os.write(s, length);
176
177 os.put(BINPUT);
178 os.put(1);
179 }
180
181 inline void writeString(const char *s) {
182 if (!s) {
183 writeNone();
184 return;
185 }
186
187 writeString(s, strlen(s));
188 }
189
190 inline void writeString(const std::string &s) {
191 writeString(s.c_str(), s.size());
192 }
193
194 inline void writeNone(void) {
195 os.put(NONE);
196 }
197
198 inline void writeBool(bool b) {
199 os.put(b ? NEWTRUE : NEWFALSE);
200 }
201
José Fonseca447576d2012-01-27 14:27:13 +0000202 inline void writeInt(uint8_t i) {
203 os.put(BININT1);
204 os.put(i);
José Fonseca299a1b32012-01-26 20:32:59 +0000205 }
206
José Fonseca447576d2012-01-27 14:27:13 +0000207 inline void writeInt(uint16_t i) {
208 if (i < 0x100) {
209 writeInt((uint8_t)i);
210 } else {
211 os.put(BININT2);
212 putInt16(i);
213 }
214 }
215
216 inline void writeInt(int32_t i) {
217 if (0 <= i && i < 0x10000) {
218 writeInt((uint16_t)i);
219 } else {
220 os.put(BININT);
221 putInt32(i);
222 }
223 }
224
225 inline void writeInt(uint32_t i) {
226 if (i < 0x8000000) {
227 writeInt((int32_t)i);
228 } else {
229 writeLong(i);
230 }
231 }
232
233 inline void writeInt(long long i) {
234 if (-0x8000000 <= i && i < 0x8000000) {
235 writeInt((int32_t)i);
236 } else {
237 writeLong(i);
238 }
239 }
240
241 inline void writeInt(unsigned long long i) {
242 if (i < 0x8000000) {
243 writeInt((int32_t)i);
244 } else {
245 writeLong(i);
246 }
247 }
248
249 inline void writeFloat(double f) {
250 union {
251 double f;
252 char c[8];
253 } u;
254
255 assert(sizeof u.f == sizeof u.c);
256 u.f = f;
257
258 os.put(BINFLOAT);
259 os.put(u.c[7]);
260 os.put(u.c[6]);
261 os.put(u.c[5]);
262 os.put(u.c[4]);
263 os.put(u.c[3]);
264 os.put(u.c[2]);
265 os.put(u.c[1]);
266 os.put(u.c[0]);
267 }
268
269protected:
270 inline void putInt16(uint16_t i) {
271 os.put( i & 0xff);
272 os.put( i >> 8 );
273 }
274
275 inline void putInt32(uint32_t i) {
276 os.put( i & 0xff);
277 os.put((i >> 8) & 0xff);
278 os.put((i >> 16) & 0xff);
279 os.put( i >> 24 );
280 }
281
282 template< class T >
283 inline void writeLong(T l) {
284 os.put(LONG1);
285
286 if (l == 0) {
287 os.put(0);
288 return;
289 }
290
291 unsigned c = 1;
292 // Same as l >> (8 * sizeof l), but without the warnings
293 T sign = l < 0 ? ~0 : 0;
294 while ((l >> (8 * c)) != sign) {
295 ++c;
296 }
297 // Add an extra byte if sign bit doesn't match
298 if (((l >> (8 * c - 1)) & 1) != ((l >> (8 * sizeof l - 1)) & 1)) {
299 ++c;
300 }
301 os.put(c);
302
303 for (unsigned i = 0; i < c; ++ i) {
304 os.put(l & 0xff);
305 l >>= 8;
306 }
José Fonseca299a1b32012-01-26 20:32:59 +0000307 }
308};
309
310#endif /* _Pickle_HPP_ */