3 * Copyright 2007,2009 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <gruel/pmt.h>
28 #include "gruel/pmt_serial_tags.h"
32 static pmt_t parse_pair(std::streambuf &sb);
34 // ----------------------------------------------------------------
36 // ----------------------------------------------------------------
39 serialize_untagged_u8(unsigned int i, std::streambuf &sb)
41 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
44 // always writes big-endian
46 serialize_untagged_u16(unsigned int i, std::streambuf &sb)
48 sb.sputc((i >> 8) & 0xff);
49 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
52 // always writes big-endian
54 serialize_untagged_u32(unsigned int i, std::streambuf &sb)
56 sb.sputc((i >> 24) & 0xff);
57 sb.sputc((i >> 16) & 0xff);
58 sb.sputc((i >> 8) & 0xff);
59 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
63 // always writes big-endian
65 serialize_untagged_u64(uint64_t i, std::streambuf &sb)
67 sb.sputc((i >> 56) & 0xff);
68 sb.sputc((i >> 48) & 0xff);
69 sb.sputc((i >> 40) & 0xff);
70 sb.sputc((i >> 32) & 0xff);
71 sb.sputc((i >> 24) & 0xff);
72 sb.sputc((i >> 16) & 0xff);
73 sb.sputc((i >> 8) & 0xff);
74 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
78 // ----------------------------------------------------------------
80 // ----------------------------------------------------------------
83 // always reads big-endian
85 deserialize_untagged_u8(uint8_t *ip, std::streambuf &sb)
87 std::streambuf::traits_type::int_type t;
94 return t != std::streambuf::traits_type::eof();
97 // always reads big-endian
99 deserialize_untagged_u16(uint16_t *ip, std::streambuf &sb)
101 std::streambuf::traits_type::int_type t;
108 i = (i << 8) | (t & 0xff);
111 return t != std::streambuf::traits_type::eof();
114 // always reads big-endian
116 deserialize_untagged_u32(uint32_t *ip, std::streambuf &sb)
118 std::streambuf::traits_type::int_type t;
125 i = (i << 8) | (t & 0xff);
127 i = (i << 8) | (t & 0xff);
129 i = (i << 8) | (t & 0xff);
132 return t != std::streambuf::traits_type::eof();
136 // always reads big-endian
138 deserialize_untagged_u64(uint64_t *ip, std::streambuf &sb)
140 std::streambuf::traits_type::int_type t;
147 i = (i << 8) | (t & 0xff);
149 i = (i << 8) | (t & 0xff);
151 i = (i << 8) | (t & 0xff);
153 i = (i << 8) | (t & 0xff);
155 i = (i << 8) | (t & 0xff);
157 i = (i << 8) | (t & 0xff);
159 i = (i << 8) | (t & 0xff);
162 return t != std::streambuf::traits_type::eof();
167 * Write portable byte-serial representation of \p obj to \p sb
169 * N.B., Circular structures cause infinite recursion.
172 pmt_serialize(pmt_t obj, std::streambuf &sb)
178 if (pmt_is_bool(obj)){
179 if (pmt_eq(obj, PMT_T))
180 return serialize_untagged_u8(PST_TRUE, sb);
182 return serialize_untagged_u8(PST_FALSE, sb);
185 if (pmt_is_null(obj))
186 return serialize_untagged_u8(PST_NULL, sb);
188 if (pmt_is_symbol(obj)){
189 const std::string s = pmt_symbol_to_string(obj);
190 size_t len = s.size();
191 ok = serialize_untagged_u8(PST_SYMBOL, sb);
192 ok &= serialize_untagged_u16(len, sb);
193 for (size_t i = 0; i < len; i++)
194 ok &= serialize_untagged_u8(s[i], sb);
198 if (pmt_is_pair(obj)){
199 ok = serialize_untagged_u8(PST_PAIR, sb);
200 ok &= pmt_serialize(pmt_car(obj), sb);
207 if (pmt_is_number(obj)){
209 if (pmt_is_integer(obj)){
210 long i = pmt_to_long(obj);
211 if (sizeof(long) > 4){
212 if (i < -2147483647 || i > 2147483647)
213 throw pmt_notimplemented("pmt_serialize (64-bit integers)", obj);
215 ok = serialize_untagged_u8(PST_INT32, sb);
216 ok &= serialize_untagged_u32(i, sb);
220 if (pmt_is_real(obj))
221 throw pmt_notimplemented("pmt_serialize (real)", obj);
223 if (pmt_is_complex(obj))
224 throw pmt_notimplemented("pmt_serialize (complex)", obj);
227 if (pmt_is_vector(obj))
228 throw pmt_notimplemented("pmt_serialize (vector)", obj);
230 if (pmt_is_uniform_vector(obj))
231 throw pmt_notimplemented("pmt_serialize (uniform-vector)", obj);
233 if (pmt_is_dict(obj))
234 throw pmt_notimplemented("pmt_serialize (dict)", obj);
237 throw pmt_notimplemented("pmt_serialize (?)", obj);
241 * Create obj from portable byte-serial representation
243 * Returns next obj from streambuf, or PMT_EOF at end of file.
244 * Throws exception on malformed input.
247 pmt_deserialize(std::streambuf &sb)
254 static char tmpbuf[1024];
256 if (!deserialize_untagged_u8(&tag, sb))
270 if (!deserialize_untagged_u16(&u16, sb))
272 if (u16 > sizeof(tmpbuf))
273 throw pmt_notimplemented("pmt_deserialize: very long symbol",
275 if (sb.sgetn(tmpbuf, u16) != u16)
277 return pmt_intern(std::string(tmpbuf, u16));
280 if (!deserialize_untagged_u32(&u32, sb))
282 return pmt_from_long((int32_t) u32);
285 return parse_pair(sb);
291 case PST_UNIFORM_VECTOR:
293 throw pmt_notimplemented("pmt_deserialize: tag value = ",
297 throw pmt_exception("pmt_deserialize: malformed input stream, tag value = ",
302 throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F);
306 * This is a mostly non-recursive implementation that allows us to
307 * deserialize very long lists w/o exhausting the evaluation stack.
309 * On entry we've already eaten the PST_PAIR tag.
312 parse_pair(std::streambuf &sb)
315 pmt_t val, expr, lastnptr, nptr;
318 // Keep appending nodes until we get a non-PAIR cdr.
322 expr = pmt_deserialize(sb); // read the car
324 nptr = pmt_cons(expr, PMT_NIL); // build new cell
325 if (pmt_is_null(lastnptr))
328 pmt_set_cdr(lastnptr, nptr);
331 if (!deserialize_untagged_u8(&tag, sb)) // get tag of cdr
332 throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F);
335 continue; // keep on looping...
337 if (tag == PST_NULL){
343 // default: push tag back and use pmt_deserialize to get the cdr
346 expr = pmt_deserialize(sb);
351 // At this point, expr contains the value of the final cdr in the list.
353 pmt_set_cdr(lastnptr, expr);
357 } /* namespace pmt */