blob: f007c491e30b5c1a109cb0e7cb3567423774477b [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIBIPP_IPP_ATTRIBUTE_H_
#define LIBIPP_IPP_ATTRIBUTE_H_
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "ipp_enums.h" // NOLINT(build/include)
#include "ipp_export.h" // NOLINT(build/include)
namespace ipp {
// Represents the current state of the attribute:
// set/unset or one of the out-of-band values.
// "unset" means that the attribute is not included in a IPP frame.
enum class AttrState : uint8_t {
unset = 0x00, // internal
set = 0x01, // internal
unsupported = 0x10, // [rfc8010]
unknown = 0x12, // [rfc8010]
novalue_ = 0x13, // [rfc8010]
not_settable = 0x15, // [rfc3380]
delete_attribute = 0x16, // [rfc3380]
admin_define = 0x17 // [rfc3380]
};
// Represents types of values hold by attributes (see [rfc8010]).
// "collection" means that the attribute has class Collection as a value.
enum class AttrType : uint8_t {
integer = 0x21,
boolean = 0x22,
enum_ = 0x23,
octetString = 0x30,
dateTime = 0x31,
resolution = 0x32,
rangeOfInteger = 0x33,
collection = 0x34, // use begCollection tag value [rfc8010]
text = 0x35, // use textWithLanguage tag value [rfc8010]
name = 0x36, // use nameWithLanguage tag value [rfc8010]
keyword = 0x44,
uri = 0x45,
uriScheme = 0x46,
charset = 0x47,
naturalLanguage = 0x48,
mimeMediaType = 0x49
};
// It is used to hold name and text values (see [rfc8010]).
// If language == "" it represents nameWithoutLanguage or textWithoutLanguage,
// otherwise it represents nameWithLanguage or textWithLanguage.
struct StringWithLanguage {
std::string value = "";
std::string language = "";
StringWithLanguage() = default;
StringWithLanguage(const std::string& value, const std::string& language)
: value(value), language(language) {}
explicit StringWithLanguage(const std::string& value) : value(value) {}
explicit StringWithLanguage(std::string&& value) : value(value) {}
operator std::string() const { return value; }
};
// Represents resolution type from [rfc8010].
struct Resolution {
int size1 = 0;
int size2 = 0;
enum Units { kDotsPerInch = 3, kDotsPerCentimeter = 4 } units = kDotsPerInch;
Resolution() = default;
Resolution(int size1, int size2, Units units = Units::kDotsPerInch)
: size1(size1), size2(size2), units(units) {}
};
// Represents rangeOfInteger type from [rfc8010].
struct RangeOfInteger {
int min_value = 0;
int max_value = 0;
RangeOfInteger() = default;
RangeOfInteger(int min_value, int max_value)
: min_value(min_value), max_value(max_value) {}
};
// Represents dateTime type from [rfc8010,rfc2579].
struct DateTime {
uint16_t year = 2000;
uint8_t month = 1; // 1..12
uint8_t day = 1; // 1..31
uint8_t hour = 0; // 0..23
uint8_t minutes = 0; // 0..59
uint8_t seconds = 0; // 0..60 (60 - leap second :-)
uint8_t deci_seconds = 0; // 0..9
uint8_t UTC_direction = '+'; // '+' / '-'
uint8_t UTC_hours = 0; // 0..13
uint8_t UTC_minutes = 0; // 0..59
};
// Functions converting basic types to string. For enums it returns empty
// string if given value is not defined.
IPP_EXPORT std::string ToString(AttrState value);
IPP_EXPORT std::string ToString(AttrType value);
IPP_EXPORT std::string ToString(bool value);
IPP_EXPORT std::string ToString(int value);
IPP_EXPORT std::string ToString(const Resolution& value);
IPP_EXPORT std::string ToString(const RangeOfInteger& value);
IPP_EXPORT std::string ToString(const DateTime& value);
// Functions extracting basic types from string.
// Returns false <=> given pointer is nullptr or given string does not
// represent a correct value.
IPP_EXPORT bool FromString(const std::string& str, bool* value);
IPP_EXPORT bool FromString(const std::string& str, int* value);
// It is defined in ipp_package.h. Represents struct-like entity with
// attributes, where each attribute must have unique name.
class Collection;
// Base class representing Attribute, contains general API for Attribute.
class IPP_EXPORT Attribute {
public:
virtual ~Attribute() = default;
// Returns a type of the attribute.
AttrType GetType() const { return type_; }
// Returns a state of an attribute. Default state is always AttrState::unset,
// setting any value with SetValues(...) switches the state to AttrState::set.
// State can be also set by hand with SetState() method.
// If (GetType() != collection): returns a state value saved in the object.
// If (GetType() == collection): the following algorithm is used:
// 1. If the attribute's state was set directly to one of out-of-band values
// (values different that AttrState::unset and AttrState::set), this value
// is returned.
// 2. If (GetState() == unset) for all members in all Collections in the
// attribute, the value AttrState::unset is returned (recursive check).
// 3. Returns AttrState::set.
AttrState GetState();
// Sets state of the attribute.
// If (GetType() != collection): it sets directly the state in the object.
// If (GetType() == collection): the following rules apply:
// * If (new_state == unset), it clears out-of-band value from the object
// and calls recursively SetState(unset) for all members in all
// Collections in the attribute.
// * If (new_state == set), it only clears out-of-band value from the object.
// * In all other cases it just sets directly the given out-of-band value in
// the object.
void SetState(AttrState new_state);
// Returns true if the attribute is a set, false if it is a single value.
bool IsASet() const { return is_a_set_; }
// Returns enum value corresponding to attributes name. If the name has
// no corresponding AttrName value, it returns AttrName::_unknown.
AttrName GetNameAsEnum() const { return name_; }
// Returns an attribute's name as a non-empty string.
virtual std::string GetName() const { return ToString(name_); }
// Returns the current number of elements (values or Collections).
// (IsASet() == false) => always returns 1.
virtual size_t GetSize() const = 0;
// Resizes a set of values or Collections if IsASet() == true.
// (IsASet() == false) => does nothing.
virtual void Resize(size_t) = 0;
// Retrieves a value from an attribute, returns true for success and
// false if the index is out of range or the value cannot be converted
// to given variable (in this case, the given variable is not modified).
// (val == nullptr) => does nothing and returns false.
// (GetType() == collection) => does nothing and returns false.
virtual bool GetValue(std::string* val, size_t index = 0) const {
return false;
}
virtual bool GetValue(StringWithLanguage* val, size_t index = 0) const {
return false;
}
virtual bool GetValue(int* val, size_t index = 0) const { return false; }
virtual bool GetValue(Resolution* val, size_t index = 0) const {
return false;
}
virtual bool GetValue(RangeOfInteger* val, size_t index = 0) const {
return false;
}
virtual bool GetValue(DateTime* val, size_t index = 0) const { return false; }
// Stores a value in given attribute's element. If the attribute is a set
// and given index is out of range, the underlying container is resized.
// Returns true for success and false if given value cannot be converted
// to internal variable or one of the following rules applies:
// (GetType() == collection) => does nothing and returns false.
// (IsASet() == false && index != 0) => does nothing and returns false.
virtual bool SetValue(const std::string& val, size_t index = 0) {
return false;
}
virtual bool SetValue(const StringWithLanguage& val, size_t index = 0) {
return false;
}
virtual bool SetValue(const int& val, size_t index = 0) { return false; }
virtual bool SetValue(const Resolution& val, size_t index = 0) {
return false;
}
virtual bool SetValue(const RangeOfInteger& val, size_t index = 0) {
return false;
}
virtual bool SetValue(const DateTime& val, size_t index = 0) { return false; }
// Returns a pointer to Collection.
// (GetType() != collection || index >= GetSize()) <=> returns nullptr.
virtual Collection* GetCollection(size_t index = 0) { return nullptr; }
protected:
// Constructor is available from derived classes only.
Attribute(AttrName name, bool is_a_set, AttrType type)
: type_(type), name_(name), is_a_set_(is_a_set) {}
const AttrType type_;
const AttrName name_;
const bool is_a_set_;
AttrState state_ = AttrState::unset;
private:
// Copy/move/assign constructors/operators are forbidden.
Attribute(const Attribute&) = delete;
Attribute(Attribute&&) = delete;
Attribute& operator=(const Attribute&) = delete;
Attribute& operator=(Attribute&&) = delete;
};
// Basic values are stored in attributes as variables of the following types:
enum InternalType : uint8_t {
kInteger, // int
kString, // std::string
kStringWithLanguage, // ipp::StringWithLanguage
kResolution, // ipp::Resolution
kRange, // ipp::RangeOfIntegers
kDateTime // ipp::DateTime
};
// General class for storing basic values, provides implementation for methods
// GetValue(...) and SetValue(...). It is not suppose to be used directly.
class IPP_EXPORT ValueAttribute : public Attribute {
public:
virtual ~ValueAttribute();
// Implementation of general API from Attribute.
size_t GetSize() const override;
void Resize(size_t) override;
bool GetValue(std::string* val, size_t index = 0) const override;
bool GetValue(StringWithLanguage* val, size_t index = 0) const override;
bool GetValue(int* val, size_t index = 0) const override;
bool GetValue(Resolution* val, size_t index = 0) const override;
bool GetValue(RangeOfInteger* val, size_t index = 0) const override;
bool GetValue(DateTime* val, size_t index = 0) const override;
bool SetValue(const std::string& val, size_t index = 0) override;
bool SetValue(const StringWithLanguage& val, size_t index = 0) override;
bool SetValue(const int& val, size_t index = 0) override;
bool SetValue(const Resolution& val, size_t index = 0) override;
bool SetValue(const RangeOfInteger& val, size_t index = 0) override;
bool SetValue(const DateTime& val, size_t index = 0) override;
protected:
// Constructor is available from derived classes only.
ValueAttribute(AttrName, bool is_a_set, AttrType, InternalType);
private:
InternalType cpp_type_;
union Data {
std::vector<int> as_int;
std::vector<std::string> as_string;
std::vector<Resolution> as_resolution;
std::vector<RangeOfInteger> as_ranges;
std::vector<DateTime> as_datetime;
std::vector<StringWithLanguage> as_string_with_language;
// We have to provide constructor and destructor because union's
// elements are not trivial. The union is initialized/deleted in
// constructor/destructor of the class.
IPP_PRIVATE Data() {}
IPP_PRIVATE ~Data() {}
} data_;
};
// These templates convert the type from specialized API to the internal type
// used to store values. Default is integer because it is used for all enum
// types.
template <typename TType>
struct AsInternalType {
static const InternalType value = InternalType::kInteger;
typedef int Type;
};
template <>
struct AsInternalType<std::string> {
static const InternalType value = InternalType::kString;
typedef std::string Type;
};
template <>
struct AsInternalType<Resolution> {
static const InternalType value = InternalType::kResolution;
typedef Resolution Type;
};
template <>
struct AsInternalType<RangeOfInteger> {
static const InternalType value = InternalType::kRange;
typedef RangeOfInteger Type;
};
template <>
struct AsInternalType<DateTime> {
static const InternalType value = InternalType::kDateTime;
typedef DateTime Type;
};
template <>
struct AsInternalType<StringWithLanguage> {
static const InternalType value = InternalType::kStringWithLanguage;
typedef StringWithLanguage Type;
};
// Final class for Attribute, represents single value from the schema.
// Template parameter defines type of the value.
template <typename TValue>
class SingleValue : public ValueAttribute {
public:
SingleValue(AttrName name, AttrType type)
: ValueAttribute(name, false, type, AsInternalType<TValue>::value) {}
// Specialized API
void Set(const TValue& val) {
SetValue(static_cast<typename AsInternalType<TValue>::Type>(val));
}
TValue Get() const {
typename AsInternalType<TValue>::Type val;
GetValue(&val);
return static_cast<TValue>(val);
}
};
// Specialization of the template above for StringWithLanguage to add
// Set(std::string).
template <>
class SingleValue<StringWithLanguage> : public ValueAttribute {
public:
SingleValue(AttrName name, AttrType type)
: ValueAttribute(
name, false, type, AsInternalType<StringWithLanguage>::value) {}
// Specialized API
void Set(const StringWithLanguage& val) {
SetValue(static_cast<StringWithLanguage>(val));
}
void Set(const std::string& val) {
SetValue(static_cast<StringWithLanguage>(val));
}
StringWithLanguage Get() const {
StringWithLanguage val;
GetValue(&val);
return val;
}
};
// Final class for Attribute, represents sets of values.
// Template parameter defines type of a single value.
template <typename TValue>
class SetOfValues : public ValueAttribute {
public:
SetOfValues(AttrName name, AttrType type)
: ValueAttribute(name, true, type, AsInternalType<TValue>::value) {}
// Specialized API
void Set(const std::vector<TValue>& vals) {
Resize(vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], i);
}
std::vector<TValue> Get() const {
std::vector<TValue> vals(GetSize());
for (size_t i = 0; i < vals.size(); ++i) {
typename AsInternalType<TValue>::Type val;
GetValue(&val, i);
vals[i] = static_cast<TValue>(val);
}
return vals;
}
void Add(const std::vector<TValue>& vals) {
const size_t old_size = GetSize();
Resize(old_size + vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], old_size + i);
}
};
// Specialization of the template above for StringWithLanguage to add
// Set/Add(std::string).
template <>
class SetOfValues<StringWithLanguage> : public ValueAttribute {
public:
SetOfValues(AttrName name, AttrType type)
: ValueAttribute(
name, true, type, AsInternalType<StringWithLanguage>::value) {}
// Specialized API
void Set(const std::vector<StringWithLanguage>& vals) {
Resize(vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], i);
}
void Set(const std::vector<std::string>& vals) {
Resize(vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], i);
}
std::vector<StringWithLanguage> Get() const {
std::vector<StringWithLanguage> vals(GetSize());
for (size_t i = 0; i < vals.size(); ++i) {
StringWithLanguage val;
GetValue(&val, i);
vals[i] = val;
}
return vals;
}
void Add(const std::vector<StringWithLanguage>& vals) {
const size_t old_size = GetSize();
Resize(old_size + vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], old_size + i);
}
void Add(const std::vector<std::string>& vals) {
const size_t old_size = GetSize();
Resize(old_size + vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], old_size + i);
}
};
// Final class for Attribute, represents sets of values that can contain names
// outside the schema.
template <typename TValue>
class OpenSetOfValues : public ValueAttribute {
public:
OpenSetOfValues(AttrName name, AttrType type)
: ValueAttribute(name, true, type, InternalType::kString) {}
// Specialized API
void Set(const std::vector<std::string>& vals) {
Resize(vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], i);
}
void Set(const std::vector<TValue>& vals) {
Resize(vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(ToString(vals[i]), i);
}
std::vector<std::string> Get() const {
std::vector<std::string> vals(GetSize());
for (size_t i = 0; i < vals.size(); ++i)
GetValue(&(vals[i]), i);
return vals;
}
void Add(const std::vector<std::string>& vals) {
const size_t old_size = GetSize();
Resize(old_size + vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(vals[i], old_size + i);
}
void Add(const std::vector<TValue>& vals) {
const size_t old_size = GetSize();
Resize(old_size + vals.size());
for (size_t i = 0; i < vals.size(); ++i)
SetValue(ToString(vals[i]), old_size + i);
}
};
// Final class for Attribute, represents attribute not defined in the schema.
class IPP_EXPORT UnknownValueAttribute : public ValueAttribute {
public:
UnknownValueAttribute(const std::string& name, bool is_a_set, AttrType type);
std::string GetName() const override { return str_name_; }
private:
std::string str_name_;
};
// Final class for Attribute, represents single IPP collection.
// Template parameter is a class derived from Collection and defines
// the structure.
template <class TCollection>
class SingleCollection : public Attribute, public TCollection {
public:
explicit SingleCollection(AttrName name)
: Attribute(name, false, AttrType::collection) {}
// Implementation of general API from Attribute.
size_t GetSize() const override { return 1; }
void Resize(size_t) override {}
Collection* GetCollection(size_t index = 0) override {
if (index == 0)
return this;
return nullptr;
}
};
// Final class for Attribute, represents set of collections from IPP spec.
// Template parameter is a class derived from Collection and defines
// the structure of a single collection.
template <class TCollection>
class SetOfCollections : public Attribute {
public:
explicit SetOfCollections(AttrName name)
: Attribute(name, true, AttrType::collection) {}
// Implementation of general API from Attribute.
size_t GetSize() const override { return collections_.size(); }
void Resize(size_t new_size) override {
while (collections_.size() < new_size)
collections_.push_back(std::make_unique<TCollection>());
collections_.resize(new_size);
}
Collection* GetCollection(size_t index = 0) override {
if (index >= collections_.size())
return nullptr;
return collections_[index].get();
}
// Specialized API
// If index is out of range, the vector is resized to (index+1).
TCollection& operator[](size_t index) {
if (index >= collections_.size())
Resize(index + 1);
return *(collections_[index]);
}
private:
std::vector<std::unique_ptr<TCollection>> collections_;
};
class IPP_EXPORT UnknownCollectionAttribute : public Attribute {
public:
UnknownCollectionAttribute(const std::string& name, bool is_a_set);
// Implementation of general API from Attribute.
std::string GetName() const override { return str_name_; }
size_t GetSize() const override { return collections_.size(); }
void Resize(size_t new_size) override;
Collection* GetCollection(size_t index = 0) override {
if (index >= collections_.size())
return nullptr;
return collections_[index].get();
}
private:
std::string str_name_;
std::vector<std::unique_ptr<Collection>> collections_;
};
} // namespace ipp
#endif // LIBIPP_IPP_ATTRIBUTE_H_