1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIBIPP_IPP_ATTRIBUTE_H_
6 #define LIBIPP_IPP_ATTRIBUTE_H_
7 
8 #include <cstdint>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 
13 #include "ipp_enums.h"  // NOLINT(build/include)
14 #include "ipp_export.h"  // NOLINT(build/include)
15 
16 namespace ipp {
17 
18 // Represents the current state of the attribute:
19 // set/unset or one of the out-of-band values.
20 // "unset" means that the attribute is not included in a IPP frame.
21 enum class AttrState : uint8_t {
22   unset = 0x00,             // internal
23   set = 0x01,               // internal
24   unsupported = 0x10,       // [rfc8010]
25   unknown = 0x12,           // [rfc8010]
26   novalue_ = 0x13,          // [rfc8010]
27   not_settable = 0x15,      // [rfc3380]
28   delete_attribute = 0x16,  // [rfc3380]
29   admin_define = 0x17       // [rfc3380]
30 };
31 
32 // Represents types of values hold by attributes (see [rfc8010]).
33 // "collection" means that the attribute has class Collection as a value.
34 enum class AttrType : uint8_t {
35   integer = 0x21,
36   boolean = 0x22,
37   enum_ = 0x23,
38   octetString = 0x30,
39   dateTime = 0x31,
40   resolution = 0x32,
41   rangeOfInteger = 0x33,
42   collection = 0x34,  // use begCollection tag value [rfc8010]
43   text = 0x35,        // use textWithLanguage tag value [rfc8010]
44   name = 0x36,        // use nameWithLanguage tag value [rfc8010]
45   keyword = 0x44,
46   uri = 0x45,
47   uriScheme = 0x46,
48   charset = 0x47,
49   naturalLanguage = 0x48,
50   mimeMediaType = 0x49
51 };
52 
53 // It is used to hold name and text values (see [rfc8010]).
54 // If language == "" it represents nameWithoutLanguage or textWithoutLanguage,
55 // otherwise it represents nameWithLanguage or textWithLanguage.
56 struct StringWithLanguage {
57   std::string value = "";
58   std::string language = "";
59   StringWithLanguage() = default;
StringWithLanguageStringWithLanguage60   StringWithLanguage(const std::string& value, const std::string& language)
61       : value(value), language(language) {}
StringWithLanguageStringWithLanguage62   explicit StringWithLanguage(const std::string& value) : value(value) {}
StringWithLanguageStringWithLanguage63   explicit StringWithLanguage(std::string&& value) : value(value) {}
stringStringWithLanguage64   operator std::string() const { return value; }
65 };
66 
67 // Represents resolution type from [rfc8010].
68 struct Resolution {
69   int size1 = 0;
70   int size2 = 0;
71   enum Units { kDotsPerInch = 3, kDotsPerCentimeter = 4 } units = kDotsPerInch;
72   Resolution() = default;
73   Resolution(int size1, int size2, Units units = Units::kDotsPerInch)
size1Resolution74       : size1(size1), size2(size2), units(units) {}
75 };
76 
77 // Represents rangeOfInteger type from [rfc8010].
78 struct RangeOfInteger {
79   int min_value = 0;
80   int max_value = 0;
81   RangeOfInteger() = default;
RangeOfIntegerRangeOfInteger82   RangeOfInteger(int min_value, int max_value)
83       : min_value(min_value), max_value(max_value) {}
84 };
85 
86 // Represents dateTime type from [rfc8010,rfc2579].
87 struct DateTime {
88   uint16_t year = 2000;
89   uint8_t month = 1;            // 1..12
90   uint8_t day = 1;              // 1..31
91   uint8_t hour = 0;             // 0..23
92   uint8_t minutes = 0;          // 0..59
93   uint8_t seconds = 0;          //  0..60 (60 - leap second :-)
94   uint8_t deci_seconds = 0;     // 0..9
95   uint8_t UTC_direction = '+';  // '+' / '-'
96   uint8_t UTC_hours = 0;        // 0..13
97   uint8_t UTC_minutes = 0;      //  0..59
98 };
99 
100 // Functions converting basic types to string. For enums it returns empty
101 // string if given value is not defined.
102 IPP_EXPORT std::string ToString(AttrState value);
103 IPP_EXPORT std::string ToString(AttrType value);
104 IPP_EXPORT std::string ToString(bool value);
105 IPP_EXPORT std::string ToString(int value);
106 IPP_EXPORT std::string ToString(const Resolution& value);
107 IPP_EXPORT std::string ToString(const RangeOfInteger& value);
108 IPP_EXPORT std::string ToString(const DateTime& value);
109 
110 // Functions extracting basic types from string.
111 // Returns false <=> given pointer is nullptr or given string does not
112 // represent a correct value.
113 IPP_EXPORT bool FromString(const std::string& str, bool* value);
114 IPP_EXPORT bool FromString(const std::string& str, int* value);
115 
116 // It is defined in ipp_package.h. Represents struct-like entity with
117 // attributes, where each attribute must have unique name.
118 class Collection;
119 
120 // Base class representing Attribute, contains general API for Attribute.
121 class IPP_EXPORT Attribute {
122  public:
123   virtual ~Attribute() = default;
124 
125   // Returns a type of the attribute.
GetType()126   AttrType GetType() const { return type_; }
127 
128   // Returns a state of an attribute. Default state is always AttrState::unset,
129   // setting any value with SetValues(...) switches the state to AttrState::set.
130   // State can be also set by hand with SetState() method.
131   // If (GetType() != collection): returns a state value saved in the object.
132   // If (GetType() == collection): the following algorithm is used:
133   // 1. If the attribute's state was set directly to one of out-of-band values
134   //    (values different that AttrState::unset and AttrState::set), this value
135   //    is returned.
136   // 2. If (GetState() == unset) for all members in all Collections in the
137   //    attribute, the value AttrState::unset is returned (recursive check).
138   // 3. Returns AttrState::set.
139   AttrState GetState();
140 
141   // Sets state of the attribute.
142   // If (GetType() != collection): it sets directly the state in the object.
143   // If (GetType() == collection): the following rules apply:
144   // * If (new_state == unset), it clears out-of-band value from the object
145   //   and calls recursively SetState(unset) for all members in all
146   //   Collections in the attribute.
147   // * If (new_state == set), it only clears out-of-band value from the object.
148   // * In all other cases it just sets directly the given out-of-band value in
149   //   the object.
150   void SetState(AttrState new_state);
151 
152   // Returns true if the attribute is a set, false if it is a single value.
IsASet()153   bool IsASet() const { return is_a_set_; }
154 
155   // Returns enum value corresponding to attributes name. If the name has
156   // no corresponding AttrName value, it returns AttrName::_unknown.
GetNameAsEnum()157   AttrName GetNameAsEnum() const { return name_; }
158 
159   // Returns an attribute's name as a non-empty string.
GetName()160   virtual std::string GetName() const { return ToString(name_); }
161 
162   // Returns the current number of elements (values or Collections).
163   // (IsASet() == false) => always returns 1.
164   virtual size_t GetSize() const = 0;
165 
166   // Resizes a set of values or Collections if IsASet() == true.
167   // (IsASet() == false) => does nothing.
168   virtual void Resize(size_t) = 0;
169 
170   // Retrieves a value from an attribute, returns true for success and
171   // false if the index is out of range or the value cannot be converted
172   // to given variable (in this case, the given variable is not modified).
173   // (val == nullptr) => does nothing and returns false.
174   // (GetType() == collection) => does nothing and returns false.
175   virtual bool GetValue(std::string* val, size_t index = 0) const {
176     return false;
177   }
178   virtual bool GetValue(StringWithLanguage* val, size_t index = 0) const {
179     return false;
180   }
181   virtual bool GetValue(int* val, size_t index = 0) const { return false; }
182   virtual bool GetValue(Resolution* val, size_t index = 0) const {
183     return false;
184   }
185   virtual bool GetValue(RangeOfInteger* val, size_t index = 0) const {
186     return false;
187   }
188   virtual bool GetValue(DateTime* val, size_t index = 0) const { return false; }
189 
190   // Stores a value in given attribute's element. If the attribute is a set
191   // and given index is out of range, the underlying container is resized.
192   // Returns true for success and false if given value cannot be converted
193   // to internal variable or one of the following rules applies:
194   // (GetType() == collection) => does nothing and returns false.
195   // (IsASet() == false && index != 0) => does nothing and returns false.
196   virtual bool SetValue(const std::string& val, size_t index = 0) {
197     return false;
198   }
199   virtual bool SetValue(const StringWithLanguage& val, size_t index = 0) {
200     return false;
201   }
202   virtual bool SetValue(const int& val, size_t index = 0) { return false; }
203   virtual bool SetValue(const Resolution& val, size_t index = 0) {
204     return false;
205   }
206   virtual bool SetValue(const RangeOfInteger& val, size_t index = 0) {
207     return false;
208   }
209   virtual bool SetValue(const DateTime& val, size_t index = 0) { return false; }
210 
211   // Returns a pointer to Collection.
212   // (GetType() != collection || index >= GetSize()) <=> returns nullptr.
213   virtual Collection* GetCollection(size_t index = 0) { return nullptr; }
214 
215  protected:
216   // Constructor is available from derived classes only.
Attribute(AttrName name,bool is_a_set,AttrType type)217   Attribute(AttrName name, bool is_a_set, AttrType type)
218       : type_(type), name_(name), is_a_set_(is_a_set) {}
219 
220   const AttrType type_;
221   const AttrName name_;
222   const bool is_a_set_;
223   AttrState state_ = AttrState::unset;
224 
225  private:
226   // Copy/move/assign constructors/operators are forbidden.
227   Attribute(const Attribute&) = delete;
228   Attribute(Attribute&&) = delete;
229   Attribute& operator=(const Attribute&) = delete;
230   Attribute& operator=(Attribute&&) = delete;
231 };
232 
233 // Basic values are stored in attributes as variables of the following types:
234 enum InternalType : uint8_t {
235   kInteger,             // int
236   kString,              // std::string
237   kStringWithLanguage,  // ipp::StringWithLanguage
238   kResolution,          // ipp::Resolution
239   kRange,               // ipp::RangeOfIntegers
240   kDateTime             // ipp::DateTime
241 };
242 
243 // General class for storing basic values, provides implementation for methods
244 // GetValue(...) and SetValue(...). It is not suppose to be used directly.
245 class IPP_EXPORT ValueAttribute : public Attribute {
246  public:
247   virtual ~ValueAttribute();
248 
249   // Implementation of general API from Attribute.
250   size_t GetSize() const override;
251   void Resize(size_t) override;
252   bool GetValue(std::string* val, size_t index = 0) const override;
253   bool GetValue(StringWithLanguage* val, size_t index = 0) const override;
254   bool GetValue(int* val, size_t index = 0) const override;
255   bool GetValue(Resolution* val, size_t index = 0) const override;
256   bool GetValue(RangeOfInteger* val, size_t index = 0) const override;
257   bool GetValue(DateTime* val, size_t index = 0) const override;
258   bool SetValue(const std::string& val, size_t index = 0) override;
259   bool SetValue(const StringWithLanguage& val, size_t index = 0) override;
260   bool SetValue(const int& val, size_t index = 0) override;
261   bool SetValue(const Resolution& val, size_t index = 0) override;
262   bool SetValue(const RangeOfInteger& val, size_t index = 0) override;
263   bool SetValue(const DateTime& val, size_t index = 0) override;
264 
265  protected:
266   // Constructor is available from derived classes only.
267   ValueAttribute(AttrName, bool is_a_set, AttrType, InternalType);
268 
269  private:
270   InternalType cpp_type_;
271   union Data {
272     std::vector<int> as_int;
273     std::vector<std::string> as_string;
274     std::vector<Resolution> as_resolution;
275     std::vector<RangeOfInteger> as_ranges;
276     std::vector<DateTime> as_datetime;
277     std::vector<StringWithLanguage> as_string_with_language;
278     // We have to provide constructor and destructor because union's
279     // elements are not trivial. The union is initialized/deleted in
280     // constructor/destructor of the class.
Data()281     IPP_PRIVATE Data() {}
~Data()282     IPP_PRIVATE ~Data() {}
283   } data_;
284 };
285 
286 // These templates convert the type from specialized API to the internal type
287 // used to store values. Default is integer because it is used for all enum
288 // types.
289 template <typename TType>
290 struct AsInternalType {
291   static const InternalType value = InternalType::kInteger;
292   typedef int Type;
293 };
294 template <>
295 struct AsInternalType<std::string> {
296   static const InternalType value = InternalType::kString;
297   typedef std::string Type;
298 };
299 template <>
300 struct AsInternalType<Resolution> {
301   static const InternalType value = InternalType::kResolution;
302   typedef Resolution Type;
303 };
304 template <>
305 struct AsInternalType<RangeOfInteger> {
306   static const InternalType value = InternalType::kRange;
307   typedef RangeOfInteger Type;
308 };
309 template <>
310 struct AsInternalType<DateTime> {
311   static const InternalType value = InternalType::kDateTime;
312   typedef DateTime Type;
313 };
314 template <>
315 struct AsInternalType<StringWithLanguage> {
316   static const InternalType value = InternalType::kStringWithLanguage;
317   typedef StringWithLanguage Type;
318 };
319 
320 // Final class for Attribute, represents single value from the schema.
321 // Template parameter defines type of the value.
322 template <typename TValue>
323 class SingleValue : public ValueAttribute {
324  public:
325   SingleValue(AttrName name, AttrType type)
326       : ValueAttribute(name, false, type, AsInternalType<TValue>::value) {}
327 
328   // Specialized API
329   void Set(const TValue& val) {
330     SetValue(static_cast<typename AsInternalType<TValue>::Type>(val));
331   }
332   TValue Get() const {
333     typename AsInternalType<TValue>::Type val;
334     GetValue(&val);
335     return static_cast<TValue>(val);
336   }
337 };
338 
339 // Specialization of the template above for StringWithLanguage to add
340 // Set(std::string).
341 template <>
342 class SingleValue<StringWithLanguage> : public ValueAttribute {
343  public:
344   SingleValue(AttrName name, AttrType type)
345       : ValueAttribute(
346             name, false, type, AsInternalType<StringWithLanguage>::value) {}
347 
348   // Specialized API
349   void Set(const StringWithLanguage& val) {
350     SetValue(static_cast<StringWithLanguage>(val));
351   }
352   void Set(const std::string& val) {
353     SetValue(static_cast<StringWithLanguage>(val));
354   }
355   StringWithLanguage Get() const {
356     StringWithLanguage val;
357     GetValue(&val);
358     return val;
359   }
360 };
361 
362 // Final class for Attribute, represents sets of values.
363 // Template parameter defines type of a single value.
364 template <typename TValue>
365 class SetOfValues : public ValueAttribute {
366  public:
367   SetOfValues(AttrName name, AttrType type)
368       : ValueAttribute(name, true, type, AsInternalType<TValue>::value) {}
369 
370   // Specialized API
371   void Set(const std::vector<TValue>& vals) {
372     Resize(vals.size());
373     for (size_t i = 0; i < vals.size(); ++i)
374       SetValue(vals[i], i);
375   }
376   std::vector<TValue> Get() const {
377     std::vector<TValue> vals(GetSize());
378     for (size_t i = 0; i < vals.size(); ++i) {
379       typename AsInternalType<TValue>::Type val;
380       GetValue(&val, i);
381       vals[i] = static_cast<TValue>(val);
382     }
383     return vals;
384   }
385   void Add(const std::vector<TValue>& vals) {
386     const size_t old_size = GetSize();
387     Resize(old_size + vals.size());
388     for (size_t i = 0; i < vals.size(); ++i)
389       SetValue(vals[i], old_size + i);
390   }
391 };
392 
393 // Specialization of the template above for StringWithLanguage to add
394 // Set/Add(std::string).
395 template <>
396 class SetOfValues<StringWithLanguage> : public ValueAttribute {
397  public:
398   SetOfValues(AttrName name, AttrType type)
399       : ValueAttribute(
400             name, true, type, AsInternalType<StringWithLanguage>::value) {}
401 
402   // Specialized API
403   void Set(const std::vector<StringWithLanguage>& vals) {
404     Resize(vals.size());
405     for (size_t i = 0; i < vals.size(); ++i)
406       SetValue(vals[i], i);
407   }
408   void Set(const std::vector<std::string>& vals) {
409     Resize(vals.size());
410     for (size_t i = 0; i < vals.size(); ++i)
411       SetValue(vals[i], i);
412   }
413   std::vector<StringWithLanguage> Get() const {
414     std::vector<StringWithLanguage> vals(GetSize());
415     for (size_t i = 0; i < vals.size(); ++i) {
416       StringWithLanguage val;
417       GetValue(&val, i);
418       vals[i] = val;
419     }
420     return vals;
421   }
422   void Add(const std::vector<StringWithLanguage>& vals) {
423     const size_t old_size = GetSize();
424     Resize(old_size + vals.size());
425     for (size_t i = 0; i < vals.size(); ++i)
426       SetValue(vals[i], old_size + i);
427   }
428   void Add(const std::vector<std::string>& vals) {
429     const size_t old_size = GetSize();
430     Resize(old_size + vals.size());
431     for (size_t i = 0; i < vals.size(); ++i)
432       SetValue(vals[i], old_size + i);
433   }
434 };
435 
436 // Final class for Attribute, represents sets of values that can contain names
437 // outside the schema.
438 template <typename TValue>
439 class OpenSetOfValues : public ValueAttribute {
440  public:
441   OpenSetOfValues(AttrName name, AttrType type)
442       : ValueAttribute(name, true, type, InternalType::kString) {}
443 
444   // Specialized API
445   void Set(const std::vector<std::string>& vals) {
446     Resize(vals.size());
447     for (size_t i = 0; i < vals.size(); ++i)
448       SetValue(vals[i], i);
449   }
450   void Set(const std::vector<TValue>& vals) {
451     Resize(vals.size());
452     for (size_t i = 0; i < vals.size(); ++i)
453       SetValue(ToString(vals[i]), i);
454   }
455   std::vector<std::string> Get() const {
456     std::vector<std::string> vals(GetSize());
457     for (size_t i = 0; i < vals.size(); ++i)
458       GetValue(&(vals[i]), i);
459     return vals;
460   }
461   void Add(const std::vector<std::string>& vals) {
462     const size_t old_size = GetSize();
463     Resize(old_size + vals.size());
464     for (size_t i = 0; i < vals.size(); ++i)
465       SetValue(vals[i], old_size + i);
466   }
467   void Add(const std::vector<TValue>& vals) {
468     const size_t old_size = GetSize();
469     Resize(old_size + vals.size());
470     for (size_t i = 0; i < vals.size(); ++i)
471       SetValue(ToString(vals[i]), old_size + i);
472   }
473 };
474 
475 // Final class for Attribute, represents attribute not defined in the schema.
476 class IPP_EXPORT UnknownValueAttribute : public ValueAttribute {
477  public:
478   UnknownValueAttribute(const std::string& name, bool is_a_set, AttrType type);
479   std::string GetName() const override { return str_name_; }
480 
481  private:
482   std::string str_name_;
483 };
484 
485 // Final class for Attribute, represents single IPP collection.
486 // Template parameter is a class derived from Collection and defines
487 // the structure.
488 template <class TCollection>
489 class SingleCollection : public Attribute, public TCollection {
490  public:
491   explicit SingleCollection(AttrName name)
492       : Attribute(name, false, AttrType::collection) {}
493 
494   // Implementation of general API from Attribute.
495   size_t GetSize() const override { return 1; }
496   void Resize(size_t) override {}
497   Collection* GetCollection(size_t index = 0) override {
498     if (index == 0)
499       return this;
500     return nullptr;
501   }
502 };
503 
504 // Final class for Attribute, represents set of collections from IPP spec.
505 // Template parameter is a class derived from Collection and defines
506 // the structure of a single collection.
507 template <class TCollection>
508 class SetOfCollections : public Attribute {
509  public:
510   explicit SetOfCollections(AttrName name)
511       : Attribute(name, true, AttrType::collection) {}
512 
513   // Implementation of general API from Attribute.
514   size_t GetSize() const override { return collections_.size(); }
515   void Resize(size_t new_size) override {
516     while (collections_.size() < new_size)
517       collections_.push_back(std::make_unique<TCollection>());
518     collections_.resize(new_size);
519   }
520   Collection* GetCollection(size_t index = 0) override {
521     if (index >= collections_.size())
522       return nullptr;
523     return collections_[index].get();
524   }
525 
526   // Specialized API
527   // If index is out of range, the vector is resized to (index+1).
528   TCollection& operator[](size_t index) {
529     if (index >= collections_.size())
530       Resize(index + 1);
531     return *(collections_[index]);
532   }
533 
534  private:
535   std::vector<std::unique_ptr<TCollection>> collections_;
536 };
537 
538 class IPP_EXPORT UnknownCollectionAttribute : public Attribute {
539  public:
540   UnknownCollectionAttribute(const std::string& name, bool is_a_set);
541 
542   // Implementation of general API from Attribute.
543   std::string GetName() const override { return str_name_; }
544   size_t GetSize() const override { return collections_.size(); }
545   void Resize(size_t new_size) override;
546   Collection* GetCollection(size_t index = 0) override {
547     if (index >= collections_.size())
548       return nullptr;
549     return collections_[index].get();
550   }
551 
552  private:
553   std::string str_name_;
554   std::vector<std::unique_ptr<Collection>> collections_;
555 };
556 
557 }  // namespace ipp
558 
559 #endif  //  LIBIPP_IPP_ATTRIBUTE_H_
560