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