blob: 54c9a7fc61985aaad083dcf868fb0f612701a057 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIBIPP_FRAME_H_
#define LIBIPP_FRAME_H_
#include <array>
#include <cstdint>
#include <utility>
#include <vector>
#include "attribute.h"
#include "colls_view.h"
#include "ipp_enums.h"
#include "ipp_export.h"
namespace ipp {
// represents operation id
typedef E_operations_supported Operation;
// represents status-code [rfc8010]
typedef E_status_code Status;
// represents the version of IPP protocol
// The first byte (MSB) of this value correspond to major version number, the
// second one to minor version number.
typedef E_ipp_versions_supported Version;
// There are methods that return error codes. The error code is usually
// returned via the last method's parameter that is optional.
// This enum contains possible values of error codes.
enum class Code {
kOK, // success (no errors)
kDataTooLong, // the payload of the frame is too large
kInvalidGroupTag, // provided GroupTag is invalid
kInvalidValueTag, // provided ValueTag is invalid
kIndexOutOfRange, // parameter 'index' is wrong
kTooManyGroups, // reached the threshold
kTooManyAttributes, // reached the threshold
kInvalidName, // incorrect attribute name
kNameConflict, // attribute with this name already exists
kIncompatibleType, // conversion between C++ type and value is not supported
kValueOutOfRange // given C++ value is out of range (invalid)
};
// The correct values of GroupTag are 0x01, 0x02, 0x04-0x0f. This function
// checks if given GroupTag is valid.
constexpr bool IsValid(GroupTag tag) {
if (tag > static_cast<GroupTag>(0x0f))
return false;
if (tag < static_cast<GroupTag>(0x01))
return false;
return (tag != static_cast<GroupTag>(0x03));
}
// This array contains all valid GroupTag values and may be used in loops like
// for (GroupTag gt: kGroupTags) ...
constexpr std::array<GroupTag, 14> kGroupTags{
static_cast<GroupTag>(0x01), static_cast<GroupTag>(0x02),
static_cast<GroupTag>(0x04), static_cast<GroupTag>(0x05),
static_cast<GroupTag>(0x06), static_cast<GroupTag>(0x07),
static_cast<GroupTag>(0x08), static_cast<GroupTag>(0x09),
static_cast<GroupTag>(0x0a), static_cast<GroupTag>(0x0b),
static_cast<GroupTag>(0x0c), static_cast<GroupTag>(0x0d),
static_cast<GroupTag>(0x0e), static_cast<GroupTag>(0x0f)};
// TODO(pawliczek) - move all limits to separate header, this one was moved here
// from ipp_parser.cc
// This parameters defines maximum number of attribute groups in single package.
constexpr size_t kMaxCountOfAttributeGroups = 20 * 1024;
class Collection;
class Attribute;
// This class represents an IPP frame (IPP request or IPP response). All
// pointers to Collection or Attribute returned by methods of this class
// point to internal objects. These objects are always owned by their Frame
// object and their lifetime does not exceed the lifetime of their owner.
class LIBIPP_EXPORT Frame {
public:
// Constructor. Create an empty frame with all basic parameters set to 0.
Frame();
// Constructor. Create a frame and set basic parameters for IPP request.
// If `set_localization_en_us` is true (default) the Group Operation
// Attributes is added to the frame with two attributes:
// * "attributes-charset"="utf-8"
// * "attributes-natural-language"="en-us"
// If `set_localization_en_us` equals false, you have to add the Group
// Operation Attributes with these two attributes by hand since they are
// required to be the first attributes in the frame (see section 4.1.4 from
// RFC 8011).
explicit Frame(Operation operation_id,
Version version_number = Version::_1_1,
int32_t request_id = 1,
bool set_localization_en_us = true);
// Constructor. The same as the previous constructor but for IPP response.
// There is no differences between frames created with this and the previous
// constructor. IPP requests and IPP responses have the same structure.
// Values of operation_id and status_code are saved in the same variable,
// they are just casted to different enums with static_cast<>(). The parameter
// `set_localization_en_us_and_status_message` works in similar way as the
// parameter `set_localization_en_us` in the constructor above but also adds
// the attribute "status-message" to the Group Operation Attributes. The value
// of the attribute is set to a string representation of the `status_code`.
// The attribute "status-message" is defined in the section 4.1.6.2 from
// RFC 8011.
explicit Frame(Status status_code,
Version version_number = Version::_1_1,
int32_t request_id = 1,
bool set_localization_en_us_and_status_message = true);
Frame(const Frame&) = delete;
Frame& operator=(const Frame&) = delete;
Frame(Frame&&) = default;
Frame& operator=(Frame&&) = default;
virtual ~Frame();
// Access IPP version number.
Version& VersionNumber();
Version VersionNumber() const;
// Access operation id or status code. OperationId() and StatusCode() refer to
// the same field, they just cast the same value to different enums. The field
// is interpreted as operation id in IPP request and as status code in IPP
// responses.
int16_t& OperationIdOrStatusCode();
int16_t OperationIdOrStatusCode() const;
Operation OperationId() const;
Status StatusCode() const;
// Access request id.
int32_t& RequestId();
int32_t RequestId() const;
// Access to payload (e.g.: document to print).
const std::vector<uint8_t>& Data() const;
// Remove the payload from the frame and return it.
std::vector<uint8_t> TakeData();
// Set the new payload in the frame. The returned value is one of:
// * Code::kOK
// * Code::kDataTooLong
Code SetData(std::vector<uint8_t>&& data);
// Provides access to groups with the given GroupTag. You can iterate over
// these groups in the following way:
// for (Collection& coll: frame.Groups(GroupTag::job_attributes)) {
// ...
// }
// or
// for (size_t i = 0; i < frame.Groups(GroupTag::job_attributes).size(); ) {
// Collection& coll = frame.Groups(GroupTag::job_attributes)[i++];
// ...
// }
// The groups are in the same order as they occur in the frame.
CollsView Groups(GroupTag tag);
ConstCollsView Groups(GroupTag tag) const;
// Return all groups of attributes in the frame in the order they were added.
// The returned vector never contains nullptr values.
std::vector<std::pair<GroupTag, Collection*>> GetGroups();
std::vector<std::pair<GroupTag, const Collection*>> GetGroups() const;
// Add a new group of attributes to the frame. The iterator to the new group
// is saved in `new_group`. The returned iterator is valid in the range
// returned by Groups(tag).
// The returned value is one of the following:
// * Code::kOK
// * Code::kInvalidGroupTag
// * Code::kTooManyGroups
// If the returned value != Code::kOK then `new_group` is not modified.
Code AddGroup(GroupTag tag, CollsView::iterator& new_group);
private:
Version version_;
int16_t operation_id_or_status_code_;
int32_t request_id_;
// Groups stored in the order they appear in the binary representation.
std::vector<std::pair<GroupTag, Collection*>> groups_;
// Content of `group_` sorted by GroupTag. The largest valid value of GroupTag
// is 0x0f (see kGroupTags above).
std::array<std::vector<Collection*>, 16> groups_by_tag_;
std::vector<uint8_t> data_;
};
} // namespace ipp
#endif // LIBIPP_FRAME_H_