messageiterator.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-or-later OR BSD-3-Clause
2 /***************************************************************************
3  * Copyright (C) 2007,2009,2010 by Rick L. Vinyard, Jr. *
4  * rvinyard@cs.nmsu.edu *
5  * *
6  * This file is part of the dbus-cxx library. *
7  ***************************************************************************/
8 #include <stdint.h>
9 #include <dbus-cxx/demangle.h>
10 #include <dbus-cxx/types.h>
11 #include <dbus-cxx/variant.h>
12 #include <dbus-cxx/demarshaling.h>
14 #include <map>
15 #include <memory>
16 #include <string>
17 #include <tuple>
18 #include <type_traits>
19 #include <vector>
20 #include "enums.h"
21 #include "error.h"
22 #include "headerlog.h"
23 #include "signature.h"
24 
25 #ifndef DBUSCXX_MESSAGEITERATOR_H
26 #define DBUSCXX_MESSAGEITERATOR_H
27 
28 #if defined(__GNUC__) && (__GNUC__ <= 8)
29  /*
30  * There seems to be a bug with G++ on versions <= 8 where the operator Variant()
31  * is trying to call the constructor instead of actually calling the operator on
32  * the iterator. This macro works around this bug
33  */
34  #define DBUSCXX_MESSAGEITERATOR_OPERATOR_VARIANT(iter) iter.operator DBus::Variant()
35  #define DBUSCXX_MESSAGEITERATOR_OPERATOR_SIGNATURE(iter) iter.operator DBus::Signature()
36  #define DBUSCXX_MESSAGEITERATOR_OPERATOR_MULTIPLE_RETURN(iter) iter.operator DBus::MultipleReturn()
37 #else
38  #define DBUSCXX_MESSAGEITERATOR_OPERATOR_VARIANT(iter) (DBus::Variant)iter
39  #define DBUSCXX_MESSAGEITERATOR_OPERATOR_SIGNATURE(iter) (DBus::Signature)iter
40  #define DBUSCXX_MESSAGEITERATOR_OPERATOR_MULTIPLE_RETURN(iter) (DBus::MultipleReturn)iter
41 #endif
42 
43 namespace DBus {
44 
45 class FileDescriptor;
46 class Message;
47 template<typename ... T> class MultipleReturn;
48 
57 
58 private:
69  const Message* message,
70  std::shared_ptr<Demarshaling> demarshal );
71 
72 public:
73 
75 
77 
78  MessageIterator( std::shared_ptr<Message> message );
79 
84  const Message* message() const;
85 
87  void invalidate();
88 
90  bool is_valid() const;
91 
93  bool has_next() const;
94 
103  bool next();
104 
106 
108 
109  bool operator==( const MessageIterator& other );
110 
112  DataType arg_type() const;
113 
119  DataType element_type() const;
120 
122  bool is_fixed() const;
123 
125  bool is_container() const;
126 
128  bool is_array() const;
129 
131  bool is_dict() const;
132 
139 
141  std::string signature() const;
142 
143  operator bool();
144  operator uint8_t();
145  operator uint16_t();
146  operator int16_t();
147  operator uint32_t();
148  operator int32_t();
149  operator uint64_t();
150  operator int64_t();
151  operator double();
152  operator std::string();
153  operator std::shared_ptr<FileDescriptor>();
154  operator Variant();
155 
156  template <typename T>
157  operator std::vector<T>() {
158  if( !this->is_array() ) {
159  throw ErrorInvalidTypecast( "MessageIterator: Extracting non array into std::vector" );
160  }
161  std::vector<T> ret;
162  get_array<T>(ret);
163 
164  return ret;
165  }
166 
167  template <typename Key, typename Data>
168  operator std::map<Key, Data>() {
169  if( !this->is_dict() ) {
170  throw ErrorInvalidTypecast( "MessageIterator: Extracting non dict into std::map" );
171  }
172 
173  return get_dict<Key, Data>();
174  }
175 
176  template <typename... T>
177  operator std::tuple<T...>() {
178  std::tuple<T...> tup;
179  get_struct<T...>( tup );
180  return tup;
181  }
182 
183  template <typename... T>
184  operator DBus::MultipleReturn<T...>() {
185  DBus::MultipleReturn<T...> multi_ret;
186  get_multiplereturn<T...>( multi_ret );
187  return multi_ret;
188  }
189 
190  bool get_bool();
191  uint8_t get_uint8();
192  uint16_t get_uint16();
193  int16_t get_int16();
194  uint32_t get_uint32();
195  int32_t get_int32();
196  uint64_t get_uint64();
197  int64_t get_int64();
198  double get_double();
199  std::string get_string();
200  std::shared_ptr<FileDescriptor> get_filedescriptor();
203 
207  template <typename T>
208  void get_array( std::vector<T>& array ) {
209  if( !this->is_array() ) { /* Should never happen */
210  throw ErrorInvalidTypecast( "MessageIterator: Extracting non array into std::vector" );
211  }
212 
213  array.clear();
214 
215  MessageIterator subiter = this->recurse();
216 
217  while( subiter.is_valid() ) {
218  //NOTE: we don't need to do subiter.next() here, because
219  //operator>> does that for us
220  T val;
221  subiter >> val;
222  array.push_back( val );
223  }
224  }
225 
226  template <typename... T>
227  void get_struct( std::tuple<T...>& tup ) {
228  MessageIterator subiter = this->recurse();
229  std::apply( [subiter]( auto&& ...arg ) mutable {
230  ( subiter >> ... >> arg );
231  },
232  tup );
233  }
234 
235  template <typename Key, typename Data>
236  void get_dict( std::map<Key, Data>& dict ) {
237  MessageIterator subiter = this->recurse();
238 
239  while( subiter.is_valid() ) {
240  MessageIterator subSubiter = subiter.recurse();
241 
242  // When we recurse the second time, our demarshaling gets aligned.
243  // This may cause the subiter to then become invalid because of
244  // the new byte offset, so we need a second is_valid() check here.
245  if( !subiter.is_valid() ){
246  break;
247  }
248 
249  while( subSubiter.is_valid() ) {
250  Key val_key;
251  Data val_data;
252 
253  subSubiter >> val_key;
254  subSubiter >> val_data;
255  dict[ val_key ] = val_data;
256  subSubiter.next();
257  }
258 
259  subiter.next();
260  }
261  }
262 
263  template <typename... T>
265  std::tuple<T...> tup;
266  std::apply( [this]( auto&& ...arg ) mutable {
267  ( *this >> ... >> arg );
268  },
269  tup );
270 
271  v.m_data = tup;
272  }
273 
274  template <typename Key, typename Data>
275  std::map<Key, Data> get_dict() {
276  std::map<Key, Data> newMap;
277  get_dict( newMap );
278  return newMap;
279  }
280 
281  template <typename Key, typename Data>
282  MessageIterator& operator>>( std::map<Key, Data>& m ) {
283  if( !this->is_dict() ) {
284  throw ErrorInvalidTypecast( "MessageIterator: Extracting non dict into std::map" );
285  }
286 
287  get_dict<Key, Data>( m );
288  this->next();
289  return *this;
290  }
291 
292  template <typename... T>
293  MessageIterator& operator>>( std::tuple<T...>& v ) {
294  this->get_struct<T...>( v );
295  this->next();
296  return *this;
297  }
298 
299  template <typename T>
300  MessageIterator& operator>>( std::vector<T>& v ) {
301  if( !this->is_array() ) {
302  throw ErrorInvalidTypecast( "MessageIterator: Extracting non array into std::vector" );
303  }
304 
305  this->get_array<T>( v );
306  this->next();
307  return *this;
308  }
309 
311  v = this->get_variant();
312  this->next();
313  return *this;
314  }
315 
316  template<typename ... T>
318  this->get_multiplereturn<T...>(v);
319  this->next();
320  return *this;
321  }
322 
323  template <typename T>
325  v = static_cast<T>( *this );
326  this->next();
327  return *this;
328  }
329 
330  template<typename T>
331  T get(){
332  T ret = (T)(*this);
333  this->next();
334  return ret;
335  }
336 
337 
338 private:
340 
347  void align( int alignment );
348 
349 private:
350  class priv_data;
351 
352  std::shared_ptr<priv_data> m_priv;
353 
354  friend class Variant;
355 };
356 
357 }
358 
359 #endif
Extraction iterator allowing values to be retrieved from a message.
Definition: messageiterator.h:56
MessageIterator()
Definition: messageiterator.cpp:69
int64_t get_int64()
Definition: messageiterator.cpp:542
int32_t get_int32()
Definition: messageiterator.cpp:526
void get_multiplereturn(MultipleReturn< T... > &v)
Definition: messageiterator.h:264
MessageIterator & operator>>(std::map< Key, Data > &m)
Definition: messageiterator.h:282
std::shared_ptr< priv_data > m_priv
Definition: messageiterator.h:350
bool is_fixed() const
True if the element type is a fixed type.
Definition: messageiterator.cpp:186
void get_array(std::vector< T > &array)
Get values in an array, pushing them back one at a time.
Definition: messageiterator.h:208
std::string signature() const
Returns the current signature of the iterator.
Definition: messageiterator.cpp:215
MessageIterator & operator>>(Variant &v)
Definition: messageiterator.h:310
SignatureIterator signature_iterator()
Definition: messageiterator.cpp:613
MessageIterator & operator>>(std::vector< T > &v)
Definition: messageiterator.h:300
uint16_t get_uint16()
Definition: messageiterator.cpp:518
MessageIterator recurse()
If the iterator points to a container recurses into the container returning a sub-iterator.
Definition: messageiterator.cpp:204
uint32_t get_uint32()
Definition: messageiterator.cpp:534
MessageIterator & operator>>(std::tuple< T... > &v)
Definition: messageiterator.h:293
T get()
Definition: messageiterator.h:331
uint64_t get_uint64()
Definition: messageiterator.cpp:550
bool is_array() const
True if the iterator points to an array.
Definition: messageiterator.cpp:196
DataType arg_type() const
Returns the argument type that the iterator points to.
Definition: messageiterator.cpp:174
bool is_dict() const
True if the iterator points to a dictionary.
Definition: messageiterator.cpp:200
MessageIterator & operator>>(MultipleReturn< T... > &v)
Definition: messageiterator.h:317
MessageIterator & operator++()
Definition: messageiterator.cpp:157
const Message * message() const
Returns a pointer to the message associated with this iterator or NULL if no message is associated.
Definition: messageiterator.cpp:98
bool is_valid() const
True if this is a valid iterator.
Definition: messageiterator.cpp:106
void invalidate()
Invalidates the iterator.
Definition: messageiterator.cpp:102
friend class Variant
Definition: messageiterator.h:354
bool operator==(const MessageIterator &other)
Definition: messageiterator.cpp:169
double get_double()
Definition: messageiterator.cpp:558
DataType element_type() const
Returns the element type of the array that the iterator points to.
Definition: messageiterator.cpp:178
void get_struct(std::tuple< T... > &tup)
Definition: messageiterator.h:227
bool next()
Moves the iterator to the next field and invalidates it if it moves beyond the last field.
Definition: messageiterator.cpp:134
bool has_next() const
True if there are any more fields left to iterate over.
Definition: messageiterator.cpp:128
void get_dict(std::map< Key, Data > &dict)
Definition: messageiterator.h:236
std::string get_string()
Definition: messageiterator.cpp:566
bool get_bool()
Definition: messageiterator.cpp:494
bool is_container() const
True if the iterator points to a container.
Definition: messageiterator.cpp:191
void align(int alignment)
Align our memory to the specified location.
Definition: messageiterator.cpp:609
Signature get_signature()
Definition: messageiterator.cpp:605
MessageIterator & operator>>(T &v)
Definition: messageiterator.h:324
std::map< Key, Data > get_dict()
Definition: messageiterator.h:275
Variant get_variant()
Definition: messageiterator.cpp:598
std::shared_ptr< FileDescriptor > get_filedescriptor()
Definition: messageiterator.cpp:578
int16_t get_int16()
Definition: messageiterator.cpp:510
uint8_t get_uint8()
Definition: messageiterator.cpp:502
This class represents a basic DBus message and also serves as a base class for the specialized messag...
Definition: message.h:43
Definition: multiplereturn.h:29
std::tuple< Ts... > m_data
Definition: multiplereturn.h:31
A SignatureIterator allows you to iterate over a given DBus signature, and to extract useful informat...
Definition: signatureiterator.h:33
Represents a DBus signature.
Definition: signature.h:74
A Variant is a type-safe union for DBus operations.
Definition: variant.h:42
Global DBus namespace, where everything happens.
Definition: callmessage.cpp:18
DataType
Definition: enums.h:52