]> git.cworth.org Git - apitrace/blob - cli/pickle.hpp
Update downloads link.
[apitrace] / cli / pickle.hpp
1 /**************************************************************************
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>
35 #include <stdint.h>
36
37 #include <ostream>
38 #include <string>
39 #include <limits>
40
41
42 class PickleWriter
43 {
44 private:
45     std::ostream &os;
46
47     /*
48      * Python pickle opcodes.  See pickle.py and pickletools.py from Python
49      * standard library for details.
50      */
51     enum Opcode {
52         MARK            = '(',
53         STOP            = '.',
54         POP             = '0',
55         POP_MARK        = '1',
56         DUP             = '2',
57         FLOAT           = 'F',
58         INT             = 'I',
59         BININT          = 'J',
60         BININT1         = 'K',
61         LONG            = 'L',
62         BININT2         = 'M',
63         NONE            = 'N',
64         PERSID          = 'P',
65         BINPERSID       = 'Q',
66         REDUCE          = 'R',
67         STRING          = 'S',
68         BINSTRING       = 'T',
69         SHORT_BINSTRING = 'U',
70         UNICODE         = 'V',
71         BINUNICODE      = 'X',
72         APPEND          = 'a',
73         BUILD           = 'b',
74         GLOBAL          = 'c',
75         DICT            = 'd',
76         EMPTY_DICT      = '}',
77         APPENDS         = 'e',
78         GET             = 'g',
79         BINGET          = 'h',
80         INST            = 'i',
81         LONG_BINGET     = 'j',
82         LIST            = 'l',
83         EMPTY_LIST      = ']',
84         OBJ             = 'o',
85         PUT             = 'p',
86         BINPUT          = 'q',
87         LONG_BINPUT     = 'r',
88         SETITEM         = 's',
89         TUPLE           = 't',
90         EMPTY_TUPLE     = ')',
91         SETITEMS        = 'u',
92         BINFLOAT        = 'G',
93
94         PROTO           = '\x80',
95         NEWOBJ          = '\x81',
96         EXT1            = '\x82',
97         EXT2            = '\x83',
98         EXT4            = '\x84',
99         TUPLE1          = '\x85',
100         TUPLE2          = '\x86',
101         TUPLE3          = '\x87',
102         NEWTRUE         = '\x88',
103         NEWFALSE        = '\x89',
104         LONG1           = '\x8a',
105         LONG4           = '\x8b',
106     };
107
108 public:
109     PickleWriter(std::ostream &_os) :
110         os(_os) {
111     }
112
113     inline void begin() {
114         os.put(PROTO);
115         os.put(2);
116     }
117
118     inline void end() {
119         os.put(STOP);
120     }
121
122     inline void beginDict() {
123         os.put(EMPTY_DICT);
124         os.put(BINPUT);
125         os.put(1);
126     }
127
128     inline void endDict() {
129     }
130
131     inline void beginItem() {
132     }
133
134     inline void beginItem(const char * name) {
135         writeString(name);
136     }
137
138     inline void beginItem(const std::string &name) {
139         beginItem(name.c_str());
140     }
141
142     inline void endItem(void) {
143         os.put(SETITEM);
144     }
145
146     inline void beginList() {
147         os.put(EMPTY_LIST);
148         os.put(BINPUT);
149         os.put(1);
150         os.put(MARK);
151     }
152
153     inline void endList(void) {
154         os.put(APPENDS);
155     }
156
157     inline void beginTuple() {
158         os.put(MARK);
159     }
160
161     inline void endTuple(void) {
162         os.put(TUPLE);
163     }
164
165     inline void writeString(const char *s, size_t length) {
166         if (!s) {
167             writeNone();
168             return;
169         }
170
171         if (length < 256) {
172             os.put(SHORT_BINSTRING);
173             os.put(length);
174         } else {
175             os.put(BINSTRING);
176             putInt32(length);
177         }
178         os.write(s, length);
179
180         os.put(BINPUT);
181         os.put(1);
182     }
183
184     inline void writeString(const char *s) {
185         if (!s) {
186             writeNone();
187             return;
188         }
189
190         writeString(s, strlen(s));
191     }
192
193     inline void writeString(const std::string &s) {
194         writeString(s.c_str(), s.size());
195     }
196
197     inline void writeNone(void) {
198         os.put(NONE);
199     }
200
201     inline void writeBool(bool b) {
202         os.put(b ? NEWTRUE : NEWFALSE);
203     }
204
205     inline void writeInt(uint8_t i) {
206         os.put(BININT1);
207         os.put(i);
208     }
209
210     inline void writeInt(uint16_t i) {
211         if (i < 0x100) {
212             writeInt((uint8_t)i);
213         } else {
214             os.put(BININT2);
215             putInt16(i);
216         }
217     }
218
219     inline void writeInt(int32_t i) {
220         if (0 <= i && i < 0x10000) {
221             writeInt((uint16_t)i);
222         } else {
223             os.put(BININT);
224             putInt32(i);
225         }
226     }
227
228     inline void writeInt(uint32_t i) {
229         if (i < 0x8000000) {
230             writeInt((int32_t)i);
231         } else {
232             writeLong(i);
233         }
234     }
235
236     inline void writeInt(long long i) {
237         if (-0x8000000 <= i && i < 0x8000000) {
238             writeInt((int32_t)i);
239         } else {
240             writeLong(i);
241         }
242     }
243
244     inline void writeInt(unsigned long long i) {
245         if (i < 0x8000000) {
246             writeInt((int32_t)i);
247         } else {
248             writeLong(i);
249         }
250     }
251
252     inline void writeFloat(double f) {
253         union {
254             double f;
255             char c[8];
256         } u;
257
258         assert(sizeof u.f == sizeof u.c);
259         u.f = f;
260
261         os.put(BINFLOAT);
262         os.put(u.c[7]);
263         os.put(u.c[6]);
264         os.put(u.c[5]);
265         os.put(u.c[4]);
266         os.put(u.c[3]);
267         os.put(u.c[2]);
268         os.put(u.c[1]);
269         os.put(u.c[0]);
270     }
271
272     inline void writeByteArray(const void *buf, size_t length) {
273         os.put(GLOBAL);
274         os << "__builtin__\nbytearray\n";
275         os.put(BINPUT);
276         os.put(1);
277         writeString(static_cast<const char *>(buf), length);
278         os.put(TUPLE1);
279         os.put(REDUCE);
280     }
281
282 protected:
283     inline void putInt16(uint16_t i) {
284         os.put( i        & 0xff);
285         os.put( i >>  8        );
286     }
287
288     inline void putInt32(uint32_t i) {
289         os.put( i        & 0xff);
290         os.put((i >>  8) & 0xff);
291         os.put((i >> 16) & 0xff);
292         os.put( i >> 24        );
293     }
294
295     template< class T >
296     inline void writeLong(T l) {
297         os.put(LONG1);
298
299         if (l == 0) {
300             os.put(0);
301             return;
302         }
303
304         // Same as l >> (8 * sizeof l), but without the warnings
305         T sign;
306         if (std::numeric_limits<T>::is_signed) {
307             sign = l < 0 ? ~0 : 0;
308         } else {
309             sign = 0;
310         }
311
312         T sl = l;
313         unsigned c = 0;
314         do {
315             ++c;
316         } while (sl >>= 8 != sign);
317
318         // Add an extra byte if sign bit doesn't match
319         if (((l >> (8 * c - 1)) & 1) != ((l >> (8 * sizeof l - 1)) & 1)) {
320             ++c;
321         }
322         os.put(c);
323
324         for (unsigned i = 0; i < c; ++ i) {
325             os.put(l & 0xff);
326             l >>= 8;
327         }
328     }
329 };
330
331 #endif /* _Pickle_HPP_ */