DeviceAtlas C++ Api documentation
common.h
1 #ifndef MOBI_MTLD_COMMON
2 #define MOBI_MTLD_COMMON
3 #include <string>
4 #include <limits.h> // need the macros rather than C++ numeric_limits so we can use as template args.
5 #include <float.h>
6 #include <set>
7 #include <ctype.h>
8 #include <string.h>
9 #include <map>
10 #include <functional>
11 #include <sys/types.h>
12 #include <vector>
13 #include <time.h>
14 #include <mtld/util.h>
15 #include <mtld/exception.h>
16 #include <stdio.h>
17 
18 #if defined(WIN32) || defined(WIN64)
19 #define strcasecmp _stricmp
20 #define strncasecmp _strnicmp
21 #define strtok_r strtok_s
22 #define strtoll _strtoi64
23 #define strtoull _strtoui64
24 #define snprintf _snprintf
25 #endif
26 
27 /*
28  * Copyright (c) DeviceAtlas Limited 2021. All Rights Reserved.
29  */
30 
31 namespace Mobi { namespace Mtld { namespace Da {
32 using namespace std;
33 
34 /*
35  * Forward declarations of classes.
36  */
37 
38 class Value;
39 class Values;
40 
41 struct attrvec : public std::map<size_t, const Value *> {
42  attrvec() : std::map<size_t, const Value *>() {}
43 };
44 
45 /*
46  * Exceptions
47  */
48 
49 
50 /*
51  * Thrown by DeviceAtlas constructor if JSON database does not
52  * match expected format
53  */
55 
56 /*
57  * Thrown by getPropertyDescr methods when the property does not exist
58  * in the atlas's vocabulary.
59  */
61 public:
62  NoSuchProperty(std::string name) { *this << "no such property \"" << name << "\""; }
63  NoSuchProperty(int idx) { *this << "no property at index " << idx; }
64 };
65 
66 /*
67  * Thrown by getProperty() methods when the given property does not have a
68  * value in the device context.
69  */
70 class NoSuchValue : public Mtld::Exception {
71 public:
72  NoSuchValue(std::string name)
73  : Mtld::Exception(std::string("no value for property ") + name)
74  {}
75 };
76 
77 /*
78  * Thrown when the type of a property differs from that requested
79  * with one of the overloaded getProperty() methods of delivery context.
80  */
82 public:
83  PropertyTypeMismatch(std::string name) : Mtld::Exception(name) {}
84 };
85 
86 /*
87  * Thrown when an incompatible conversion routine is called on a Value
88  * (eg, calling strval() on a Value that has a type of JSON::Integer
89  */
91 public:
92  ValueTypeMismatch() : Mtld::Exception("value type mismatch") {}
93 };
94 
95 /*
96  * Thrown when parsing client properties if key name is not a known type
97  * identifying character.
98  */
100 public:
101  char typec;
102  InvalidPropertyType(char typec_) : Mtld::Exception("invalid property type") , typec(typec_) {
103  *this << ": " << typec;
104  }
105 };
106 
108 public:
109  MissingDataException() : Mtld::Exception("no data file loaded") {}
110 };
111 
112 // Thrown for ill-formed Data content.
113 class FormatError : public Mtld::Exception {};
114 class OverflowError : public FormatError {};
115 
116 /*
117  * Possible types of a property, as encoded in the first character of the
118  * properties name in the Data property name, or implied by the Data type.
119  * For values, we only distinguish ints and strings, as bools are recorded
120  * as 0 and 1 for false and true.
121  *
122  * Note we only record the type for values to deal with discrepancies in
123  * the data
124  */
125 enum PropertyType { Integer, String, Bool, Float, Set };
126 
127 /*
128  * Represents the value of a property extracted from the atlas.
129  * The type of a value comes from the underlying Data type: it
130  * should be possible to avoid representing this here, and just
131  * store it in the property, but some values have types that don't
132  * match the type in the property in some data files.
133  */
134 
135 typedef std::vector<Value *> valueset;
136 
137 std::ostream &
138 operator<<(ostream &, const valueset &);
139 
140 class DA_EXPORT Value {
141 public:
142  union {
143  const char *strval;
144  float floatval;
145  long longval;
146  } u;
147  valueset set;
148  PropertyType type;
149  Value()
150  : set(0),
151  type(String)
152  {
153  u.strval = 0;
154  }
155  const char *strval() const {
156  if (type != String)
157  throw ValueTypeMismatch();
158  return u.strval;
159  }
160  float floatval() const {
161  if (type != Float)
162  throw ValueTypeMismatch();
163  return u.floatval;
164  }
165  const valueset setval() const {
166  if (type != Set)
167  throw ValueTypeMismatch();
168  return set;
169  }
170  long longval() const {
171  if (type != Integer)
172  throw ValueTypeMismatch();
173  return u.longval;
174  }
175  operator bool() const;
176  operator std::string() const;
177  operator long() const;
178  operator float() const;
179  int compare(const Value &) const;
180  // compat
181  std::string toString() const { return std::string(*this); }
182 };
183 
184 
185 /*
186  * A property is a combination of type and name.
187  * The index represents the offset in the JSON array that this property
188  * was retrieved from.
189  */
190 class DA_EXPORT Property {
191 public:
192  size_t index;
193  const char *name;
194  PropertyType type;
195 };
196 
197 struct DA_EXPORT ValueChecker {
198  template<typename signedT>
199  static signedT atoi(const char *);
200  template<typename unsignedT>
201  static unsignedT atou(const char *);
202  template<typename realT>
203  static realT atof(const char *);
204 };
205 
206 struct DA_EXPORT CaseInsensitiveLess : public binary_function<std::string, std::string, bool> {
207  bool operator()(const std::string & a, const std::string & b) const {
208  return strncasecmp(a.c_str(), b.c_str(), b.size()) < 0;
209  }
210 };
211 // Case-insensitive map of string->string, used for header values.
212 typedef std::map<std::string, std::string, CaseInsensitiveLess> HeaderMap;
213 
214 /*
215  * defaultHeaderPriorities[n] is a null-terminated array of header names,
216  * in most-significant to least significant order, representing the actual
217  * HTTP header names to use as a lookup for tree "n" for properties for
218  * that device. This is overrideable when constructing the HttpHeaders
219  * object
220  */
221 DA_EXPORT extern const char **defaultHeaderPriorities[];
222 
223 /*
224  * HttpHeaders represents the evidence used to look up the DeviceAtlas
225  * for properties of a specific client. Each field of the evidence array
226  * represents the value of the header used for the lookup of the tree
227  * at the same index in the DeviceAtlas. e.g., HttpHeaders::evidence[UA]
228  * is used to match against DeviceAtlas::tree[UA]
229  */
230 struct DA_EXPORT CommonHttpHeaders {
231  CommonHttpHeaders() {}
232 };
233 
234 /*
235  * Represents the content of the DeviceAtlas JSON data. Once constructed
236  * this object should be considered const: all methods are reentrant.
237  */
238 
239 typedef std::vector<const Property *> propvec;
240 class DA_EXPORT CommonDeviceAtlas {
241  explicit CommonDeviceAtlas(const CommonDeviceAtlas &) {/* no copy construction */}
242 protected:
243  Values *values;
244 
245  /*
246  * Because most memory allocation is done at construction, to be released
247  * at destruction, we can use a simplified allocation strategy: memory
248  * allocated from this allocator is only free'd when the allocator itself
249  * is destroyed.
250  */
251 
252  // comparison functor for propByNameMap
253  class constcharless {
254  public:
255  bool operator()(const char *l, const char *r) const {
256  return strcmp(l, r) < 0;
257  }
258  };
259 
260  Util::Alloc<4096> allocator;
261  // Maps a property name to its associated Property descriptor.
262  typedef std::map<const char *, const Property *, constcharless> propByNameMap;
263  propByNameMap propertiesByName;
264 
265  // Properties, in JSON order
266  propvec properties;
267  propvec &getProperties() { return properties; }
268  const propvec &getProperties() const { return properties; }
269 
270 public:
271  const Property &addProperty(const char *name, PropertyType type);
272  const Property *findPropertyDescr(const char *p) const;
273  // look up a Property descriptor by name or index.
274  const Property &getPropertyDescr(const char *p) const;
275  const Property &getPropertyDescr(size_t off) const;
276  // This allows a find without a throw.
277  size_t getPropertyCount() const { return getProperties().size(); }
282  const propvec& getPropertyNames() const { return getProperties(); }
283 
284  // copy C string using this atlas's allocator.
285  char *strdup(const char *);
286  char *strdup(const char *, size_t);
287 
288  CommonDeviceAtlas() : values(0) {}
289  virtual ~CommonDeviceAtlas() {}
290  virtual int getDataRevision() const = 0;
291  virtual time_t getDataGeneration() const = 0;
292 };
293 
294 class DA_EXPORT CommonDeliveryContext {
295 public:
296  /*
297  * Allocator for memory that will be required for the lifetime of
298  * the DeliveryContext
299  * This is first so it can be used during construction
300  */
301  Util::Alloc<1024 * 3> allocator;
302 
303 
305 
306  const Value **globalAttrs; // indexed by property id.
307 
308  // Create a context reflecting the properties of the device
309  // identified by the HttpHeaders object.
311  virtual ~CommonDeliveryContext() {}
312  char *strdup(const char *from, size_t len = -1);
313  // std-style const iterator for all properties.
314  virtual size_t size() const = 0;
315  virtual bool empty() = 0;
316 
317  // Get value of selected properties from the device.
318 
319  // This is the canonical getProperty, which all others delegate to
320  void getProperty(const Property &prop, const Value *&value);
321 
322  // Get property of a specific assumed type.
323  void getProperty(const Property &prop, int &value);
324  void getProperty(const Property &prop, const char *&value);
325  void getProperty(const Property &prop, bool &value);
326 
327  virtual const Value *findProperty(const Property &p) const = 0;
328  virtual const Value *findProperty(size_t) const = 0;
329  virtual void setProperty(const Property &, const Value *) = 0;
330  virtual void setProperty(size_t, const Value *) = 0;
331  virtual const Property &getPropertyDescr(const char *, PropertyType *) = 0;
332  virtual const Property &getPropertyDescr(size_t idx) const = 0;
333  /*
334  * convenience methods to look up property descriptors from const char *
335  * by looking up the property descriptor as required
336  */
337  void getProperty(const char *prop, const Value *&value)
338  { getProperty(getPropertyDescr(prop, 0), value); }
339  void getProperty(const char *prop, int &value)
340  { getProperty(getPropertyDescr(prop, 0), value); }
341  void getProperty(const char *prop, const char *&value)
342  { getProperty(getPropertyDescr(prop, 0), value); }
343  void getProperty(const char *prop, bool &value)
344  { getProperty(getPropertyDescr(prop, 0), value); }
345 
346  bool hasProperty(const Property &prop) { return findProperty(prop.index) != 0; }
347  /*
348  * @brief checks presence of the requested property
349  * and the equality with the value found
350  * tocheck should be type compatible with underlying property value though
351  * @param propname
352  * @param tocheck
353  */
354  template <typename T>
355  bool contains(const char *propname, T tocheck);
356 
357  // Accessors
358  virtual const Value *operator[](const Property &) const = 0;
359  virtual const Value *operator[](const char *propname) const = 0;
360 };
361 DA_EXPORT std::ostream &operator<<(std::ostream &, const PropertyType &);
362 DA_EXPORT std::ostream &operator<<(std::ostream &, const Property &);
363 static inline std::ostream &operator << (std::ostream &os, const Value &v)
364 { return os << std::string(v); }
365 template<>
366 inline bool CommonDeliveryContext::contains<const char *>(const char *, const char *);
367 
368 #include <mtld/common.tpp>
369 
370 }}}
371 
372 // pretty-printer for stream output
373 #endif
Definition: common.h:206
Definition: common.h:230
Definition: exception.h:16
Definition: common.h:60
Definition: common.h:41
Definition: common.h:114
Definition: common.h:190
Definition: common.h:107
Definition: common.h:197
Definition: common.h:90
Definition: common.h:70
Definition: common.h:240
Definition: binary.h:13
Definition: common.h:113
Definition: common_priv.h:36
const propvec & getPropertyNames() const
Returns the Json&#39;s properties list.
Definition: common.h:282
Definition: common.h:140