3 * Copyright 2007 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.
28 #include "pmt_serial_tags.h"
30 static pmt_t parse_pair(std::streambuf &sb);
32 // ----------------------------------------------------------------
34 // ----------------------------------------------------------------
37 serialize_untagged_u8(unsigned int i, std::streambuf &sb)
39 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
42 // always writes big-endian
44 serialize_untagged_u16(unsigned int i, std::streambuf &sb)
46 sb.sputc((i >> 8) & 0xff);
47 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
50 // always writes big-endian
52 serialize_untagged_u32(unsigned int i, std::streambuf &sb)
54 sb.sputc((i >> 24) & 0xff);
55 sb.sputc((i >> 16) & 0xff);
56 sb.sputc((i >> 8) & 0xff);
57 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
61 // always writes big-endian
63 serialize_untagged_u64(uint64_t i, std::streambuf &sb)
65 sb.sputc((i >> 56) & 0xff);
66 sb.sputc((i >> 48) & 0xff);
67 sb.sputc((i >> 40) & 0xff);
68 sb.sputc((i >> 32) & 0xff);
69 sb.sputc((i >> 24) & 0xff);
70 sb.sputc((i >> 16) & 0xff);
71 sb.sputc((i >> 8) & 0xff);
72 return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof();
76 // ----------------------------------------------------------------
78 // ----------------------------------------------------------------
81 // always reads big-endian
83 deserialize_untagged_u8(uint8_t *ip, std::streambuf &sb)
85 std::streambuf::traits_type::int_type t;
92 return t != std::streambuf::traits_type::eof();
95 // always reads big-endian
97 deserialize_untagged_u16(uint16_t *ip, std::streambuf &sb)
99 std::streambuf::traits_type::int_type t;
106 i = (i << 8) | (t & 0xff);
109 return t != std::streambuf::traits_type::eof();
112 // always reads big-endian
114 deserialize_untagged_u32(uint32_t *ip, std::streambuf &sb)
116 std::streambuf::traits_type::int_type t;
123 i = (i << 8) | (t & 0xff);
125 i = (i << 8) | (t & 0xff);
127 i = (i << 8) | (t & 0xff);
130 return t != std::streambuf::traits_type::eof();
134 // always reads big-endian
136 deserialize_untagged_u64(uint64_t *ip, std::streambuf &sb)
138 std::streambuf::traits_type::int_type t;
145 i = (i << 8) | (t & 0xff);
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);
160 return t != std::streambuf::traits_type::eof();
165 * Write portable byte-serial representation of \p obj to \p sb
167 * N.B., Circular structures cause infinite recursion.
170 pmt_serialize(pmt_t obj, std::streambuf &sb)
176 if (pmt_is_bool(obj)){
177 if (pmt_eq(obj, PMT_T))
178 return serialize_untagged_u8(PST_TRUE, sb);
180 return serialize_untagged_u8(PST_FALSE, sb);
183 if (pmt_is_null(obj))
184 return serialize_untagged_u8(PST_NULL, sb);
186 if (pmt_is_symbol(obj)){
187 const std::string s = pmt_symbol_to_string(obj);
188 size_t len = s.size();
189 ok = serialize_untagged_u8(PST_SYMBOL, sb);
190 ok &= serialize_untagged_u16(len, sb);
191 for (size_t i = 0; i < len; i++)
192 ok &= serialize_untagged_u8(s[i], sb);
196 if (pmt_is_pair(obj)){
197 ok = serialize_untagged_u8(PST_PAIR, sb);
198 ok &= pmt_serialize(pmt_car(obj), sb);
205 if (pmt_is_number(obj)){
207 if (pmt_is_integer(obj)){
208 long i = pmt_to_long(obj);
209 if (sizeof(long) > 4){
210 if (i < -2147483647 || i > 2147483647)
211 throw pmt_notimplemented("pmt_serialize (64-bit integers)", obj);
213 ok = serialize_untagged_u8(PST_INT32, sb);
214 ok &= serialize_untagged_u32(i, sb);
218 if (pmt_is_real(obj))
219 throw pmt_notimplemented("pmt_serialize (real)", obj);
221 if (pmt_is_complex(obj))
222 throw pmt_notimplemented("pmt_serialize (complex)", obj);
225 if (pmt_is_vector(obj))
226 throw pmt_notimplemented("pmt_serialize (vector)", obj);
228 if (pmt_is_uniform_vector(obj))
229 throw pmt_notimplemented("pmt_serialize (uniform-vector)", obj);
231 if (pmt_is_dict(obj))
232 throw pmt_notimplemented("pmt_serialize (dict)", obj);
235 throw pmt_notimplemented("pmt_serialize (?)", obj);
239 * Create obj from portable byte-serial representation
241 * Returns next obj from streambuf, or PMT_EOF at end of file.
242 * Throws exception on malformed input.
245 pmt_deserialize(std::streambuf &sb)
252 static char tmpbuf[1024];
254 if (!deserialize_untagged_u8(&tag, sb))
268 if (!deserialize_untagged_u16(&u16, sb))
270 if (u16 > sizeof(tmpbuf))
271 throw pmt_notimplemented("pmt_deserialize: very long symbol",
273 if (sb.sgetn(tmpbuf, u16) != u16)
275 return pmt_intern(std::string(tmpbuf, u16));
278 if (!deserialize_untagged_u32(&u32, sb))
280 return pmt_from_long((int32_t) u32);
283 return parse_pair(sb);
289 case PST_UNIFORM_VECTOR:
291 throw pmt_notimplemented("pmt_deserialize: tag value = ",
295 throw pmt_exception("pmt_deserialize: malformed input stream, tag value = ",
300 throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F);
304 * This is a mostly non-recursive implementation that allows us to
305 * deserialize very long lists w/o exhausting the evaluation stack.
307 * On entry we've already eaten the PST_PAIR tag.
310 parse_pair(std::streambuf &sb)
313 pmt_t val, expr, lastnptr, nptr;
316 // Keep appending nodes until we get a non-PAIR cdr.
320 expr = pmt_deserialize(sb); // read the car
322 nptr = pmt_cons(expr, PMT_NIL); // build new cell
323 if (pmt_is_null(lastnptr))
326 pmt_set_cdr(lastnptr, nptr);
329 if (!deserialize_untagged_u8(&tag, sb)) // get tag of cdr
330 throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F);
333 continue; // keep on looping...
335 if (tag == PST_NULL){
341 // default: push tag back and use pmt_deserialize to get the cdr
344 expr = pmt_deserialize(sb);
349 // At this point, expr contains the value of the final cdr in the list.
351 pmt_set_cdr(lastnptr, expr);