]> git.cworth.org Git - apitrace/blob - common/pickle.hpp
Merge branch 'profile-gui'
[apitrace] / common / 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
40
41 class PickleWriter
42 {
43 private:
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
93         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',
105     };
106
107 public:
108     PickleWriter(std::ostream &_os) :
109         os(_os) {
110     }
111
112     inline void begin() {
113         os.put(PROTO);
114         os.put(2);
115     }
116
117     inline void end() {
118         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
164     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);
175             putInt32(length);
176         }
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
204     inline void writeInt(uint8_t i) {
205         os.put(BININT1);
206         os.put(i);
207     }
208
209     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
271     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
281 protected:
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
303         unsigned c = 1;
304         // Same as l >> (8 * sizeof l), but without the warnings
305         T sign = l < 0 ? ~0 : 0;
306         while ((l >> (8 * c)) != sign) {
307             ++c;
308         }
309         // Add an extra byte if sign bit doesn't match
310         if (((l >> (8 * c - 1)) & 1) != ((l >> (8 * sizeof l - 1)) & 1)) {
311             ++c;
312         }
313         os.put(c);
314
315         for (unsigned i = 0; i < c; ++ i) {
316             os.put(l & 0xff);
317             l >>= 8;
318         }
319     }
320 };
321
322 #endif /* _Pickle_HPP_ */