blob: 3ab437560273d571d09f973dbc78d34f256a7ce8 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file contains definitions for working with data encoded in CHIP TLV format.
*
* CHIP TLV (Tag-Length-Value) is a generalized encoding method for simple structured data. It
* shares many properties with the commonly used JSON serialization format while being considerably
* more compact over the wire.
*/
#pragma once
#include <lib/core/CHIPError.h>
#include <lib/core/CHIPTLVTags.h>
#include <lib/core/CHIPTLVTypes.h>
#include <lib/support/BitFlags.h>
#include <lib/support/BitMask.h>
#include <lib/support/DLLUtil.h>
#include <lib/support/EnforceFormat.h>
#include <lib/support/ScopedBuffer.h>
#include <lib/support/Span.h>
#include <lib/support/TypeTraits.h>
#include <lib/support/logging/Constants.h>
#include <stdarg.h>
#include <stdlib.h>
#include <type_traits>
/**
* @namespace chip::TLV
*
* Definitions for working with data encoded in CHIP TLV format.
*
* CHIP TLV is a generalized encoding method for simple structured data. It shares many properties
* with the commonly used JSON serialization format while being considerably more compact over the wire.
*/
namespace chip {
namespace TLV {
constexpr inline uint8_t operator|(TLVElementType lhs, TLVTagControl rhs)
{
return static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs);
}
constexpr inline uint8_t operator|(TLVTagControl lhs, TLVElementType rhs)
{
return static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs);
}
enum
{
kTLVControlByte_NotSpecified = 0xFFFF
};
class TLVBackingStore;
/**
* Provides a memory efficient parser for data encoded in CHIP TLV format.
*
* TLVReader implements a forward-only, “pull-style” parser for CHIP TLV data. The TLVReader
* object operates as a cursor that can be used to iterate over a sequence of TLV elements
* and interpret their contents. When positioned on an element, applications can make calls
* to the reader's Get() methods to query the current element’s type and tag, and to extract
* any associated value. The reader’s Next() method is used to advance from element to element.
*
* A TLVReader object is always positioned either before, on or after a TLV element. When first
* initialized, a TLVReader is positioned immediately before the first element of the encoding.
* To begin reading, an application must make an initial call to the Next() method to position
* the reader on the first element. When a container element is encountered--either a structure,
* an array or a path--the OpenContainer() or EnterContainer() methods can be used to iterate
* through the contents of the container.
*
* When the reader reaches the end of a TLV encoding, or the last element within a container,
* it signals the application by returning a CHIP_END_OF_TLV error from the Next() method.
* The reader will continue to return CHIP_END_OF_TLV until it is reinitialized, or the current
* container is exited (via CloseContainer() / ExitContainer()).
*
* A TLVReader object can parse data directly from a fixed input buffer, or from memory provided
* by a TLVBackingStore.
*/
class DLL_EXPORT TLVReader
{
friend class TLVWriter;
friend class TLVUpdater;
public:
/**
* Initializes a TLVReader object from another TLVReader object.
*
* @param[in] aReader A read-only reference to the TLVReader to initialize
* this from.
*
*/
void Init(const TLVReader & aReader);
/**
* Initializes a TLVReader object to read from a single input buffer.
*
* @param[in] data A pointer to a buffer containing the TLV data to be parsed.
* @param[in] dataLen The length of the TLV data to be parsed.
*
*/
void Init(const uint8_t * data, size_t dataLen);
/**
* Initializes a TLVReader object to read from a single input buffer
* represented as a span.
*
* @param[in] data A byte span to read from
*
*/
void Init(const ByteSpan & data) { Init(data.data(), data.size()); }
/**
* Initializes a TLVReader object to read from a single input buffer
* represented as byte array.
*
* @param[in] data A byte buffer to read from
*
*/
template <size_t N>
void Init(const uint8_t (&data)[N])
{
Init(data, N);
}
/**
* Initializes a TLVReader object to read from a TLVBackingStore.
*
* Parsing begins at the backing store's start position and continues until the
* end of the data in the buffer, or maxLen bytes have been parsed.
*
* @param[in] backingStore A reference to a TLVBackingStore providing the TLV data to be parsed.
* @param[in] maxLen The maximum number of bytes to parse. Defaults to the amount of data
* in the input buffer.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval other Other error codes returned by TLVBackingStore::OnInit().
*/
CHIP_ERROR Init(TLVBackingStore & backingStore, uint32_t maxLen = UINT32_MAX);
/**
* Advances the TLVReader object to the next TLV element to be read.
*
* The Next() method positions the reader object on the next element in a TLV encoding that resides
* in the same containment context. In particular, if the reader is positioned at the outer-most
* level of a TLV encoding, calling Next() will advance the reader to the next, top-most element.
* If the reader is positioned within a TLV container element (a structure, array or path), calling
* Next() will advance the reader to the next member element of the container.
*
* Since Next() constrains reader motion to the current containment context, calling Next() when
* the reader is positioned on a container element will advance @em over the container, skipping
* its member elements (and the members of any nested containers) until it reaches the first element
* after the container.
*
* When there are no further elements within a particular containment context the Next() method will
* return a #CHIP_END_OF_TLV error and the position of the reader will remain unchanged.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element.
* @retval #CHIP_END_OF_TLV If no further elements are available.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the reader encountered an invalid or unsupported TLV element
* type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the reader encountered a TLV tag in an invalid context.
* @retval #CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG
* If the reader encountered a implicitly-encoded TLV tag for which
* the corresponding profile id is unknown.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Next();
/**
* Advances the TLVReader object to the next TLV element to be read, asserting the tag of
* the new element.
*
* The Next(Tag expectedTag) method is a convenience method that has the
* same behavior as Next(), but also verifies that the tag of the new TLV element matches
* the supplied argument.
*
* @param[in] expectedTag The expected tag for the next element.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element.
* @retval #CHIP_END_OF_TLV If no further elements are available.
* @retval #CHIP_ERROR_UNEXPECTED_TLV_ELEMENT
* If the tag associated with the new element does not match the
* value of the @p expectedTag argument.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the reader encountered an invalid or unsupported TLV
* element type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the reader encountered a TLV tag in an invalid context.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Next(Tag expectedTag);
/**
* Advances the TLVReader object to the next TLV element to be read, asserting the type and tag of
* the new element.
*
* The Next(TLVType expectedType, Tag expectedTag) method is a convenience method that has the
* same behavior as Next(), but also verifies that the type and tag of the new TLV element match
* the supplied arguments.
*
* @param[in] expectedType The expected data type for the next element.
* @param[in] expectedTag The expected tag for the next element.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element.
* @retval #CHIP_END_OF_TLV If no further elements are available.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the type of the new element does not match the value
* of the @p expectedType argument.
* @retval #CHIP_ERROR_UNEXPECTED_TLV_ELEMENT
* If the tag associated with the new element does not match the
* value of the @p expectedTag argument.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the reader encountered an invalid or unsupported TLV
* element type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the reader encountered a TLV tag in an invalid context.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Next(TLVType expectedType, Tag expectedTag);
/**
* Returns the type of the current TLV element.
*
* @return A TLVType value describing the data type of the current TLV element. If the reader
* is not positioned on a TLV element, the return value will be kTLVType_NotSpecified.
*/
TLVType GetType() const;
/**
* Returns the tag associated with current TLV element.
*
* The value returned by GetTag() can be used with the tag utility functions (IsProfileTag(),
* IsContextTag(), ProfileIdFromTag(), etc.) to determine the type of tag and to extract various tag
* field values.
*
* @note If the reader is not positioned on a TLV element when GetTag() is called, the return value
* is undefined. Therefore whenever the position of the reader is uncertain applications should call
* GetType() to determine if the reader is position on an element (GetType() != kTLVType_NotSpecified)
* before calling GetTag().
*
* @return An unsigned integer containing information about the tag associated with the current
* TLV element.
*/
Tag GetTag() const { return mElemTag; }
/**
* Returns the length of data associated with current TLV element.
*
* Data length only applies to elements of type UTF8 string or byte string. For UTF8 strings, the
* value returned is the number of bytes in the string, not the number of characters.
*
* @return The length (in bytes) of data associated with the current TLV element, or 0 if the
* current element is not a UTF8 string or byte string, or if the reader is not
* positioned on an element.
*/
uint32_t GetLength() const;
/**
* Returns the control byte associated with current TLV element.
*
* Ideally, nobody ever needs to know about the control byte and only the
* internal implementation of TLV should have access to it. But, nevertheless,
* having access to the control byte is helpful for debugging purposes by the
* TLV Debug Utilities (that try to decode the tag control byte when pretty
* printing the TLV buffer contents).
*
* @note Unless you really know what you are doing, please refrain from using
* this method and the associated control byte information.
*
* @return An unsigned integer containing the control byte associated with
* the current TLV element. kTLVControlByte_NotSpecified is
* returned if the reader is not positioned @em on an element.
*/
uint16_t GetControlByte() const { return mControlByte; }
/**
* Get the value of the current element as a bool type.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV boolean type, or the
* reader is not positioned on an element.
*/
CHIP_ERROR Get(bool & v);
/**
* Get the value of the current element as an 8-bit signed integer.
*
* If the encoded integer value is larger than the output data type the resultant value will be
* truncated.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
* unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(int8_t & v);
/**
* Get the value of the current element as a 16-bit signed integer.
*
* If the encoded integer value is larger than the output data type the resultant value will be
* truncated.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
* unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(int16_t & v);
/**
* Get the value of the current element as a 32-bit signed integer.
*
* If the encoded integer value is larger than the output data type the resultant value will be
* truncated.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
* unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(int32_t & v);
/**
* Get the value of the current element as a 64-bit signed integer.
*
* If the encoded integer value is larger than the output data type the resultant value will be
* truncated.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
* unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(int64_t & v);
/**
* Get the value of the current element as an 8-bit unsigned integer.
*
* If the encoded integer value is larger than the output data type the resultant value will be
* truncated. Similarly, if the encoded integer value is negative, the value will be converted
* to unsigned.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
* unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(uint8_t & v);
/**
* Get the value of the current element as a 16-bit unsigned integer.
*
* If the encoded integer value is larger than the output data type the resultant value will be
* truncated. Similarly, if the encoded integer value is negative, the value will be converted
* to unsigned.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
* unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(uint16_t & v);
/**
* Get the value of the current element as a 32-bit unsigned integer.
*
* If the encoded integer value is larger than the output data type the resultant value will be
* truncated. Similarly, if the encoded integer value is negative, the value will be converted
* to unsigned.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(uint32_t & v);
/**
* Get the value of the current element as a 64-bit unsigned integer.
*
* If the encoded integer value is negative, the value will be converted to unsigned.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV integer type (signed or
* unsigned), or the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(uint64_t & v);
/**
* Get the value of the current element as a double-precision floating point number.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV floating point type, or
* the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(double & v);
/**
* Get the value of the current element as a single-precision floating point number.
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV floating point type, or
* the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(float & v);
/**
* Get the value of the current element as a ByteSpan
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV bytes array, or
* the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(ByteSpan & v);
/**
* Get the value of the current element as a FixedByteSpan
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV bytes array, or
* the reader is not positioned on an element.
*
*/
template <size_t N>
CHIP_ERROR Get(FixedByteSpan<N> & v)
{
const uint8_t * val;
ReturnErrorOnFailure(GetDataPtr(val));
VerifyOrReturnError(GetLength() == N, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
v = FixedByteSpan<N>(val);
return CHIP_NO_ERROR;
}
/**
* Get the value of the current element as a CharSpan
*
* @param[out] v Receives the value associated with current TLV element.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV character string, or
* the reader is not positioned on an element.
*
*/
CHIP_ERROR Get(CharSpan & v);
/**
* Get the value of the current element as an enum value, if it's an integer
* value that fits in the enum type.
*
* @param[out] v Receives the value associated with current TLV element.
*/
template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
CHIP_ERROR Get(T & v)
{
std::underlying_type_t<T> val;
ReturnErrorOnFailure(Get(val));
v = static_cast<T>(val);
return CHIP_NO_ERROR;
}
/**
* Get the value of the current element as a BitFlags value, if it's an integer
* value that fits in the BitFlags type.
*
* @param[out] v Receives the value associated with current TLV element.
*/
template <typename T>
CHIP_ERROR Get(BitFlags<T> & v)
{
std::underlying_type_t<T> val;
ReturnErrorOnFailure(Get(val));
v.SetRaw(val);
return CHIP_NO_ERROR;
}
/**
* Get the value of the current element as a BitMask value, if it's an integer
* value that fits in the BitMask type.
*
* @param[out] v Receives the value associated with current TLV element.
*/
template <typename T>
CHIP_ERROR Get(BitMask<T> & v)
{
std::underlying_type_t<T> val;
ReturnErrorOnFailure(Get(val));
v.SetRaw(val);
return CHIP_NO_ERROR;
}
/**
* Get the value of the current byte or UTF8 string element.
*
* To determine the required input buffer size, call the GetLength() method before calling GetBytes().
*
* @note The data output by this method is NOT null-terminated.
*
* @param[in] buf A pointer to a buffer to receive the string data.
* @param[in] bufSize The size in bytes of the buffer pointed to by @p buf.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV byte or UTF8 string, or
* the reader is not positioned on an element.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If the supplied buffer is too small to hold the data associated
* with the current element.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR GetBytes(uint8_t * buf, size_t bufSize);
/**
* Allocates and returns a buffer containing the value of the current byte or UTF8 string.
*
* This method creates a buffer for and returns a copy of the data associated with the byte
* or UTF-8 string element at the current position. Memory for the buffer is obtained with
* Platform::MemoryAlloc() and should be freed with Platform::MemoryFree() by the caller when
* it is no longer needed.
*
* @note The data returned by this method is NOT null-terminated.
*
* @param[out] buf A reference to a pointer to which a heap-allocated buffer of
* @p dataLen bytes will be assigned on success.
* @param[out] dataLen A reference to storage for the size, in bytes, of @p buf on
* success.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV byte or UTF8 string, or
* the reader is not positioned on an element.
* @retval #CHIP_ERROR_NO_MEMORY If memory could not be allocated for the output buffer.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR DupBytes(uint8_t *& buf, uint32_t & dataLen);
/**
* Get the value of the current byte or UTF8 string element as a null terminated string.
*
* To determine the required input buffer size, call the GetLength() method before calling GetBytes().
* The input buffer should be at least one byte bigger than the string length to accommodate the null
* character.
*
* @param[in] buf A pointer to a buffer to receive the byte string data.
* @param[in] bufSize The size in bytes of the buffer pointed to by @p buf.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV byte or UTF8 string, or
* the reader is not positioned on an element.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If the supplied buffer is too small to hold the data associated
* with the current element.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR GetString(char * buf, size_t bufSize);
/**
* Allocates and returns a buffer containing the null-terminated value of the current byte or UTF8
* string.
*
* This method creates a buffer for and returns a null-terminated copy of the data associated with
* the byte or UTF-8 string element at the current position. Memory for the buffer is obtained with
* Platform::MemoryAlloc() and should be freed with chip::Platform::MemoryFree() by the caller when
* it is no longer needed.
*
* @param[out] buf A reference to a pointer to which a heap-allocated buffer of
* will be assigned on success.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV byte or UTF8 string, or
* the reader is not positioned on an element.
* @retval #CHIP_ERROR_NO_MEMORY If memory could not be allocated for the output buffer.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR DupString(char *& buf);
/**
* Get a pointer to the initial encoded byte of a TLV byte or UTF8 string element.
*
* This method returns a direct pointer to the encoded string value within the underlying input buffer
* if a non-zero length string payload is present. To succeed, the method requires that the entirety of the
* string value be present in a single buffer. Otherwise the method returns #CHIP_ERROR_TLV_UNDERRUN.
* This makes the method of limited use when reading data from multiple discontiguous buffers.
*
* If no string data is present (i.e the length is zero), data shall be updated to point to null.
*
* @param[out] data A reference to a const pointer that will receive a pointer to
* the underlying string data.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV byte or UTF8 string, or the
* reader is not positioned on an element.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely or the value
* of the current string element is not contained within a single
* contiguous buffer.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR GetDataPtr(const uint8_t *& data);
/**
* Prepares a TLVReader object for reading the members of TLV container element.
*
* The EnterContainer() method prepares the current TLVReader object to begin reading the member
* elements of a TLV container (a structure, array or path). For every call to EnterContainer()
* applications must make a corresponding call to ExitContainer().
*
* When EnterContainer() is called the TLVReader object must be positioned on the container element
* to be read. The method takes as an argument a reference to a TLVType value which will be used
* to save the context of the reader while it is reading the container.
*
* When the EnterContainer() method returns, the reader is positioned immediately @em before the
* first member of the container. Repeatedly calling Next() will advance the reader through the members
* of the collection until the end is reached, at which point the reader will return CHIP_END_OF_TLV.
*
* Once the application has finished reading a container it can continue reading the elements after
* the container by calling the ExitContainer() method.
*
* @param[out] outerContainerType A reference to a TLVType value that will receive the context
* of the reader.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE If the current element is not positioned on a container element.
*
*/
CHIP_ERROR EnterContainer(TLVType & outerContainerType);
/**
* Completes the reading of a TLV container and prepares a TLVReader object to read elements
* after the container.
*
* The ExitContainer() method restores the state of a TLVReader object after a call to
* EnterContainer(). For every call to EnterContainer() applications must make a corresponding
* call to ExitContainer(), passing the context value returned by the EnterContainer() method.
*
* When ExitContainer() returns, the reader is positioned immediately before the first element that
* follows the container. From this point an application can use the Next() method to advance
* through any remaining elements.
*
* Once EnterContainer() has been called, applications can call ExitContainer() on a reader at any
* point in time, regardless of whether all elements in the underlying container have been read.
*
* @note Any changes made to the configuration of the reader between the calls to EnterContainer()
* and ExitContainer() are NOT undone by the call to ExitContainer(). For example, a change to the
* implicit profile id (@p ImplicitProfileId) will not be reversed when a container is exited. Thus
* it is the application's responsibility to adjust the configuration accordingly at the appropriate
* times.
*
* @param[in] outerContainerType The TLVType value that was returned by the EnterContainer() method.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE If OpenContainer() has not been called on the reader, or if
* the container reader does not match the one passed to the
* OpenContainer() method.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the reader encountered an invalid or unsupported TLV element type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the reader encountered a TLV tag in an invalid context.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR ExitContainer(TLVType outerContainerType);
/**
* Initializes a new TLVReader object for reading the members of a TLV container element.
*
* The OpenContainer() method initializes a new TLVReader object for reading the member elements of a
* TLV container (a structure, array or path). When OpenContainer() is called, the current TLVReader
* object must be positioned on the container element to be read. The method takes as its sole argument
* a reference to a new reader that will be initialized to read the container. This reader is known as
* the <em>container reader</em> while the reader on which OpenContainer() is called is known as the <em>parent
* reader</em>.
*
* When the OpenContainer() method returns, the container reader is positioned immediately before the
* first member of the container. Calling Next() on the container reader will advance through the members
* of the collection until the end is reached, at which point the reader will return CHIP_END_OF_TLV.
*
* While the container reader is open, applications must not make calls on or otherwise alter the state
* of the parent reader. Once an application has finished using the container reader it must close it
* by calling CloseContainer() on the parent reader, passing the container reader as an argument.
* Applications may close the container reader at any point, with or without reading all elements
* contained in the underlying container. After the container reader is closed, applications may
* continue their use of the parent reader.
*
* The container reader inherits various configuration properties from the parent reader. These are:
*
* @li The implicit profile id (ImplicitProfileId)
* @li The application data pointer (AppData)
* @li The GetNextBuffer function pointer
*
* @note The EnterContainer() method can be used as an alternative to OpenContainer() to read a
* container element without initializing a new reader object.
*
* @param[out] containerReader A reference to a TLVReader object that will be initialized for
* reading the members of the current container element. Any data
* associated with the supplied object is overwritten.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE If the current element is not positioned on a container element.
*
*/
CHIP_ERROR OpenContainer(TLVReader & containerReader);
/**
* Completes the reading of a TLV container after a call to OpenContainer().
*
* The CloseContainer() method restores the state of a parent TLVReader object after a call to
* OpenContainer(). For every call to OpenContainer() applications must make a corresponding
* call to CloseContainer(), passing a reference to the same container reader to both methods.
*
* When CloseContainer() returns, the parent reader is positioned immediately before the first
* element that follows the container. From this point an application can use the Next() method
* to advance through any remaining elements.
*
* Applications can call close CloseContainer() on a parent reader at any point in time, regardless
* of whether all elements in the underlying container have been read. After CloseContainer() has
* been called, the application should consider the container reader 'de-initialized' and must not
* use it further without re-initializing it.
*
* @param[in] containerReader A reference to the TLVReader object that was supplied to the
* OpenContainer() method.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE If OpenContainer() has not been called on the reader, or if
* the container reader does not match the one passed to the
* OpenContainer() method.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the reader encountered an invalid or unsupported TLV
* element type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the reader encountered a TLV tag in an invalid context.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR CloseContainer(TLVReader & containerReader);
/**
* Returns the type of the container within which the TLVReader is currently reading.
*
* The GetContainerType() method returns the type of the TLV container within which the TLVReader
* is reading. If the TLVReader is positioned at the outer-most level of a TLV encoding (i.e. before,
* on or after the outer-most TLV element), the method will return kTLVType_NotSpecified.
*
* @return The TLVType of the current container, or kTLVType_NotSpecified if the TLVReader is not
* positioned within a container.
*/
TLVType GetContainerType() const { return mContainerType; }
/**
* Verifies that the TLVReader object is at the end of a TLV container.
*
* The VerifyEndOfContainer() method verifies that there are no further TLV elements to be read
* within the current TLV container. This is a convenience method that is equivalent to calling
* Next() and checking for a return value of CHIP_END_OF_TLV.
*
* @note When there are more TLV elements in the collection, this method will change the position
* of the reader.
*
* @retval #CHIP_NO_ERROR If there are no further TLV elements to be read.
* @retval #CHIP_ERROR_UNEXPECTED_TLV_ELEMENT
* If another TLV element was found in the collection.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the reader encountered an invalid or unsupported TLV element
* type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the reader encountered a TLV tag in an invalid context.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR VerifyEndOfContainer();
/**
* Returns the total number of bytes read since the reader was initialized.
*
* @return Total number of bytes read since the reader was initialized.
*/
uint32_t GetLengthRead() const { return mLenRead; }
/**
* Returns the total number of bytes that can be read until the max read length is reached.
*
* @return Total number of bytes that can be read until the max read length is reached.
*/
uint32_t GetRemainingLength() const { return mMaxLen - mLenRead; }
/**
* Return the total number of bytes for the TLV data
* @return the total number of bytes for the TLV data
*/
uint32_t GetTotalLength() const { return mMaxLen; }
/**
* Returns the stored backing store.
*
* @return the stored backing store.
*/
TLVBackingStore * GetBackingStore() { return mBackingStore; }
/**
* Gets the point in the underlying input buffer that corresponds to the reader's current position.
*
* @note Depending on the type of the current element, GetReadPoint() will return a pointer that
* is some number of bytes *after* the first byte of the element. For string types (UTF8 and byte
* strings), the pointer will point to the first byte of the string's value. For container types
* (structures, arrays and paths), the pointer will point to the first member element within the
* container. For all other types, the pointer will point to the byte immediately after the element's
* encoding.
*
* @return A pointer into underlying input buffer that corresponds to the reader's current position.
*/
const uint8_t * GetReadPoint() const { return mReadPoint; }
/**
* Advances the TLVReader object to immediately after the current TLV element.
*
* The Skip() method positions the reader object immediately @em after the current TLV element, such
* that a subsequent call to Next() will advance the reader to the following element. Like Next(),
* if the reader is positioned on a container element at the time of the call, the members of the
* container will be skipped. If the reader is not positioned on any element, its position remains
* unchanged.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element.
* @retval #CHIP_END_OF_TLV If no further elements are available.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the reader encountered an invalid or unsupported TLV
* element type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the reader encountered a TLV tag in an invalid context.
* @retval other Other CHIP or platform error codes returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Skip();
/**
* Position the destination reader on the next element with the given tag within this reader's current container context
*
* @param[in] tagInApiForm The destination context tag value
* @param[in] destReader The destination TLV reader value that was located by given tag
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned at the given tag
* @retval #CHIP_END_OF_TLV If the given tag cannot be found
* @retval other Other CHIP or platform error codes
*/
CHIP_ERROR FindElementWithTag(Tag tagInApiForm, TLVReader & destReader) const;
/**
* Count how many elements remain in the currently-open container. Will
* fail with CHIP_ERROR_INCORRECT_STATE if not currently in a container.
*
* @param[out] size On success, set to the number of items following the
* current reader position in the container.
*/
CHIP_ERROR CountRemainingInContainer(size_t * size) const;
/**
* The profile id to be used for profile tags encoded in implicit form.
*
* When the reader encounters a profile-specific tag that has been encoded in implicit form, it
* uses the value of the @p ImplicitProfileId property as the assumed profile id for the tag.
*
* By default, the @p ImplicitProfileId property is set to kProfileIdNotSpecified. When decoding
* TLV that contains implicitly-encoded tags, applications must set @p ImplicitProfileId prior
* to reading any TLV elements having such tags. The appropriate profile id is usually dependent
* on the context of the application or protocol being spoken.
*
* If an implicitly-encoded tag is encountered while @p ImplicitProfileId is set to
* kProfileIdNotSpecified, the reader will return a #CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG error.
*/
uint32_t ImplicitProfileId;
/**
* A pointer field that can be used for application-specific data.
*/
void * AppData;
protected:
Tag mElemTag;
uint64_t mElemLenOrVal;
TLVBackingStore * mBackingStore;
const uint8_t * mReadPoint;
const uint8_t * mBufEnd;
uint32_t mLenRead;
uint32_t mMaxLen;
TLVType mContainerType;
uint16_t mControlByte;
private:
bool mContainerOpen;
protected:
bool IsContainerOpen() const { return mContainerOpen; }
void SetContainerOpen(bool aContainerOpen) { mContainerOpen = aContainerOpen; }
CHIP_ERROR ReadElement();
void ClearElementState();
CHIP_ERROR SkipData();
CHIP_ERROR SkipToEndOfContainer();
CHIP_ERROR VerifyElement();
Tag ReadTag(TLVTagControl tagControl, const uint8_t *& p) const;
CHIP_ERROR EnsureData(CHIP_ERROR noDataErr);
CHIP_ERROR ReadData(uint8_t * buf, uint32_t len);
CHIP_ERROR GetElementHeadLength(uint8_t & elemHeadBytes) const;
TLVElementType ElementType() const;
};
/*
* A TLVReader that is backed by a scoped memory buffer that is owned by the reader
*/
class ScopedBufferTLVReader : public TLVReader
{
public:
/*
* Construct and initialize the reader by taking ownership of the provided scoped buffer.
*/
ScopedBufferTLVReader(Platform::ScopedMemoryBuffer<uint8_t> && buffer, size_t dataLen) { Init(std::move(buffer), dataLen); }
ScopedBufferTLVReader() {}
/*
* Initialize the reader by taking ownership of a passed in scoped buffer.
*/
void Init(Platform::ScopedMemoryBuffer<uint8_t> && buffer, size_t dataLen)
{
mBuffer = std::move(buffer);
TLVReader::Init(mBuffer.Get(), dataLen);
}
/*
* Take back the buffer owned by the reader and transfer its ownership to
* the provided buffer reference. This also re-initializes the reader with
* a null buffer to prevent further use of the reader.
*/
void TakeBuffer(Platform::ScopedMemoryBuffer<uint8_t> & buffer)
{
buffer = std::move(mBuffer);
TLVReader::Init(nullptr, 0);
}
private:
Platform::ScopedMemoryBuffer<uint8_t> mBuffer;
};
/**
* A TLVReader that is guaranteed to be backed by a single contiguous buffer.
* This allows it to expose some additional methods that allow consumers to
* directly access the data in that buffer in a safe way that is guaranteed to
* work as long as the reader object stays in scope.
*/
class ContiguousBufferTLVReader : public TLVReader
{
public:
ContiguousBufferTLVReader() : TLVReader() {}
/**
* Init with input buffer as ptr + length pair.
*/
void Init(const uint8_t * data, size_t dataLen) { TLVReader::Init(data, dataLen); }
/**
* Init with input buffer as ByteSpan.
*/
void Init(const ByteSpan & data) { Init(data.data(), data.size()); }
/**
* Init with input buffer as byte array.
*/
template <size_t N>
void Init(const uint8_t (&data)[N])
{
Init(data, N);
}
/**
* Allow opening a container, with a new ContiguousBufferTLVReader reading
* that container. See TLVReader::OpenContainer for details.
*/
CHIP_ERROR OpenContainer(ContiguousBufferTLVReader & containerReader);
/**
* Get the value of the current UTF8 string as a Span<const char> pointing
* into the TLV data. Consumers may need to copy the data elsewhere as
* needed (e.g. before releasing the reader and its backing buffer if they
* plan to use the data after that point).
*
* @param[out] data A Span<const char> representing the string data.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV UTF8 string, or
* the reader is not positioned on an element.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely (i.e. the string length was "too big").
*
*/
CHIP_ERROR GetStringView(Span<const char> & data);
/**
* Get the value of the current octet string as a ByteSpan pointing into the
* TLV data. Consumers may need to copy the data elsewhere as needed
* (e.g. before releasing the reader and its backing buffer if they plan to
* use the data after that point).
*
* @param[out] data A ByteSpan representing the string data.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the current element is not a TLV octet string, or
* the reader is not positioned on an element.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended prematurely (i.e. the string length was "too big").
*
*/
CHIP_ERROR GetByteView(ByteSpan & data);
};
/**
* Provides a memory efficient encoder for writing data in CHIP TLV format.
*
* TLVWriter implements a forward-only, stream-style encoder for CHIP TLV data. Applications
* write data to an encoding by calling one of the writer's Put() methods, passing associated
* tag and value information as necessary. Similarly applications can encode TLV container types
* (structures, arrays or paths) by calling the writer's OpenContainer() or EnterContainer()
* methods.
*
* A TLVWriter object can write data directly to a fixed output buffer, or to memory provided by
* a TLVBackingStore.
*/
class DLL_EXPORT TLVWriter
{
friend class TLVUpdater;
public:
/**
* Initializes a TLVWriter object to write into a single output buffer.
*
* @note Applications must call Finalize() on the writer before using the contents of the output
* buffer.
*
* @param[in] buf A pointer to the buffer into which TLV should be written.
* @param[in] maxLen The maximum number of bytes that should be written to the output buffer.
*
*/
void Init(uint8_t * buf, size_t maxLen);
/**
* Initializes a TLVWriter object to write into a single output buffer
* represented by a MutableSpan. See documentation for the two-arg Init()
* form for details.
*
*/
void Init(const MutableByteSpan & data) { Init(data.data(), data.size()); }
/**
* Initializes a TLVWriter object to write into a single output buffer
* represented by a fixed-size byte array. See documentation for the
* two-arg Init() form for details.
*
*/
template <size_t N>
void Init(uint8_t (&data)[N])
{
Init(data, N);
}
/**
* Initializes a TLVWriter object to write into memory provided by a TLVBackingStore.
*
* @note Applications must call Finalize() on the writer before using the contents of the buffer.
*
* @param[in] backingStore A TLVBackingStore providing memory, which must outlive the TVLWriter.
* @param[in] maxLen The maximum number of bytes that should be written to the output buffer.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval other Other error codes returned by TLVBackingStore::OnInit().
*/
CHIP_ERROR Init(TLVBackingStore & backingStore, uint32_t maxLen = UINT32_MAX);
/**
* Finish the writing of a TLV encoding.
*
* The Finalize() method completes the process of writing a TLV encoding to the underlying output
* buffer. The method must be called by the application before it uses the contents of the buffer.
* Finalize() can only be called when there are no container writers open for the current writer.
* (See @p OpenContainer()).
*
* @retval #CHIP_NO_ERROR If the encoding was finalized successfully.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval other Other CHIP or platform-specific errors returned by the configured
* FinalizeBuffer() function.
*/
CHIP_ERROR Finalize();
/**
* Reserve some buffer for encoding future fields.
*
* @retval #CHIP_NO_ERROR Successfully reserved required buffer size.
* @retval #CHIP_ERROR_NO_MEMORY The reserved buffer size cannot fits into the remaining buffer size.
*/
CHIP_ERROR ReserveBuffer(uint32_t aBufferSize)
{
VerifyOrReturnError(mRemainingLen >= aBufferSize, CHIP_ERROR_NO_MEMORY);
mReservedSize += aBufferSize;
mRemainingLen -= aBufferSize;
return CHIP_NO_ERROR;
}
/**
* Release previously reserved buffer.
*
* @retval #CHIP_NO_ERROR Successfully released reserved buffer size.
* @retval #CHIP_ERROR_NO_MEMORY The released buffer is larger than previously reserved buffer size.
*/
CHIP_ERROR UnreserveBuffer(uint32_t aBufferSize)
{
VerifyOrReturnError(mReservedSize >= aBufferSize, CHIP_ERROR_NO_MEMORY);
mReservedSize -= aBufferSize;
mRemainingLen += aBufferSize;
return CHIP_NO_ERROR;
}
/**
* Encodes a TLV signed integer value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] v The value to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Put(Tag tag, int8_t v);
/**
* Encodes a TLV signed integer value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] v The value to be encoded.
* @param[in] preserveSize True if the value should be encoded in the same number of bytes as
* at the input type. False if value should be encoded in the minimum
* number of bytes necessary to represent the value. Note: Applications
* are strongly encouraged to set this parameter to false.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Put(Tag tag, int8_t v, bool preserveSize);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v)
*/
CHIP_ERROR Put(Tag tag, int16_t v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v, bool preserveSize)
*/
CHIP_ERROR Put(Tag tag, int16_t v, bool preserveSize);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v)
*/
CHIP_ERROR Put(Tag tag, int32_t v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v, bool preserveSize)
*/
CHIP_ERROR Put(Tag tag, int32_t v, bool preserveSize);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v)
*/
CHIP_ERROR Put(Tag tag, int64_t v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v, bool preserveSize)
*/
CHIP_ERROR Put(Tag tag, int64_t v, bool preserveSize);
/**
* Encodes a TLV unsigned integer value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] v The value to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Put(Tag tag, uint8_t v);
/**
* Encodes a TLV unsigned integer value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] v The value to be encoded.
* @param[in] preserveSize True if the value should be encoded in the same number of bytes as
* at the input type. False if value should be encoded in the minimum
* number of bytes necessary to represent the value. Note: Applications
* are strongly encouraged to set this parameter to false.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Put(Tag tag, uint8_t v, bool preserveSize);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v)
*/
CHIP_ERROR Put(Tag tag, uint16_t v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v, bool preserveSize)
*/
CHIP_ERROR Put(Tag tag, uint16_t v, bool preserveSize);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v)
*/
CHIP_ERROR Put(Tag tag, uint32_t v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v, bool preserveSize)
*/
CHIP_ERROR Put(Tag tag, uint32_t v, bool preserveSize);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v)
*/
CHIP_ERROR Put(Tag tag, uint64_t v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v, bool preserveSize)
*/
CHIP_ERROR Put(Tag tag, uint64_t v, bool preserveSize);
/**
* Encodes a TLV floating point value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] v The value to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Put(Tag tag, double v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, double v)
*/
CHIP_ERROR Put(Tag tag, float v);
/**
* Encodes a TLV byte string value using ByteSpan class.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] data A ByteSpan object containing the bytes string to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR Put(Tag tag, ByteSpan data);
/**
* static_cast to enumerations' underlying type when data is an enumeration.
*/
template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
CHIP_ERROR Put(Tag tag, T data)
{
return Put(tag, to_underlying(data));
}
/**
*
* Encodes an unsigned integer with bits corresponding to the flags set when data is a BitFlags
*/
template <typename T>
CHIP_ERROR Put(Tag tag, BitFlags<T> data)
{
return Put(tag, data.Raw());
}
/**
*
* Encodes an unsigned integer with bits corresponding to the flags set when data is a BitMask
*/
template <typename T>
CHIP_ERROR Put(Tag tag, BitMask<T> data)
{
return Put(tag, data.Raw());
}
/**
* Encodes a TLV boolean value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] v The value to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR PutBoolean(Tag tag, bool v);
/**
* @overload CHIP_ERROR TLVWriter::Put(Tag tag, bool v)
*/
CHIP_ERROR Put(Tag tag, bool v)
{
/*
* In TLV, boolean values are encoded as standalone tags without actual values, so we have a separate
* PutBoolean method.
*/
return PutBoolean(tag, v);
}
/**
* Encodes a TLV byte string value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] buf A pointer to a buffer containing the bytes string to be encoded.
* @param[in] len The number of bytes to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR PutBytes(Tag tag, const uint8_t * buf, uint32_t len);
/**
* Encodes a TLV UTF8 string value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] buf A pointer to the null-terminated UTF-8 string to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR PutString(Tag tag, const char * buf);
/**
* Encodes a TLV UTF8 string value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] buf A pointer to the UTF-8 string to be encoded.
* @param[in] len The length (in bytes) of the string to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR PutString(Tag tag, const char * buf, uint32_t len);
/**
* Encodes a TLV UTF8 string value that's passed in as a Span.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] str A Span containing a pointer and a length of the string to be encoded.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR PutString(Tag tag, Span<const char> str);
/**
* @brief
* Encode the string output formatted according to the format in the TLV element.
*
* PutStringF is an analog of a sprintf where the output is stored in
* a TLV element as opposed to a character buffer. When extended
* printf functionality is available, the function is able to output
* the result string into a discontinuous underlying storage. The
* implementation supports the following printf enhancements:
*
* -- The platform supplies a callback-based `vcbprintf` that provides
* the ability to call a custom callback in place of putchar.
*
* -- The platform supplies a variant of `vsnprintf` called
* `vsnprintf_ex`, that behaves exactly like vsnprintf except it
* has provisions for omitting the first `n` characters of the
* output.
*
* Note that while the callback-based function may be the simplest and
* use the least amount of code, the `vsprintf_ex` variety of
* functions will consume less stack.
*
* If neither of the above is available, the function will allocate a
* temporary buffer to hold the output, using Platform::MemoryAlloc().
*
* @param[in] tag The TLV tag to be encoded with the value, or @p
* AnonymousTag() if the value should be encoded without
* a tag. Tag values should be constructed with one of
* the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
*
* @param[in] fmt The format string used to format the argument list.
* Follows the same syntax and rules as the format
* string for `printf` family of functions.
*
* @param[in] ... A list of arguments to be formatted in the output value
* according to fmt.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
*
* @retval other If underlying calls to TLVWriter methods --
* `WriteElementHead` or `GetNewBuffer` -- failed, their
* error is immediately forwarded up the call stack.
*/
// The ENFORCE_FORMAT args are "off by one" because this is a class method,
// with an implicit "this" as first arg.
CHIP_ERROR PutStringF(Tag tag, const char * fmt, ...) ENFORCE_FORMAT(3, 4);
/**
* @brief
* Encode the string output formatted according to the format in the TLV element.
*
* PutStringF is an analog of a sprintf where the output is stored in
* a TLV element as opposed to a character buffer. When extended
* printf functionality is available, the function is able to output
* the result string into a discontinuous underlying storage. The
* implementation supports the following printf enhancements:
*
* -- The platform supplies a callback-based `vcbprintf` that provides
* the ability to call a custom callback in place of putchar.
*
* -- The platform supplies a variant of `vsnprintf` called
* `vsnprintf_ex`, that behaves exactly like vsnprintf except it
* has provisions for omitting the first `n` characters of the
* output.
*
* Note that while the callback-based function may be the simplest and
* use the least amount of code, the `vsprintf_ex` variety of
* functions will consume less stack.
*
* If neither of the above is available, the function will allocate a
* temporary buffer to hold the output, using Platform::MemoryAlloc().
*
* @param[in] tag The TLV tag to be encoded with the value, or @p
* AnonymousTag() if the value should be encoded without
* a tag. Tag values should be constructed with one of
* the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
*
* @param[in] fmt The format string used to format the argument list.
* Follows the same syntax and rules as the format
* string for `printf` family of functions.
*
* @param[in] ap A list of arguments to be formatted in the output value
* according to fmt.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
*
* @retval other If underlying calls to TLVWriter methods --
* `WriteElementHead` or `GetNewBuffer` -- failed, their
* error is immediately forwarded up the call stack.
*/
// The ENFORCE_FORMAT args are "off by one" because this is a class method,
// with an implicit "this" as first arg.
CHIP_ERROR VPutStringF(Tag tag, const char * fmt, va_list ap) ENFORCE_FORMAT(3, 0);
/**
* Encodes a TLV null value.
*
* @param[in] tag The TLV tag to be encoded with the value, or @p AnonymousTag() if the
* value should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR PutNull(Tag tag);
/**
* Copies a TLV element from a reader object into the writer.
*
* The CopyElement() method encodes a new TLV element whose type, tag and value are taken from a TLVReader
* object. When the method is called, the supplied reader object is expected to be positioned on the
* source TLV element. The newly encoded element will have the same type, tag and contents as the input
* container. If the supplied element is a TLV container (structure, array or path), the entire contents
* of the container will be copied.
*
* @note This method requires the supplied TVLReader object to be reading from a single, contiguous
* input buffer that contains the entirety of the underlying TLV encoding. Supplying a reader in any
* other mode has undefined behavior.
*
* @param[in] reader A reference to a TLVReader object identifying a pre-encoded TLV
* element that should be copied.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE
* If the supplied reader is not positioned on an element.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_TLV_UNDERRUN
* If the underlying TLV encoding associated with the supplied reader ended
* prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the supplied reader encountered an invalid or unsupported TLV element
* type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the supplied reader encountered a TLV tag in an invalid context,
* or if the supplied tag is invalid or inappropriate in the context in
* which the new container is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* GetNewBuffer() or FinalizeBuffer() functions, or by the GetNextBuffer()
* function associated with the reader object.
*
*/
CHIP_ERROR CopyElement(TLVReader & reader);
/**
* Copies a TLV element from a reader object into the writer.
*
* The CopyElement() method encodes a new TLV element whose type and value are taken from a TLVReader
* object. When the method is called, the supplied reader object is expected to be positioned on the
* source TLV element. The newly encoded element will have the same type and contents as the input
* container, however the tag will be set to the specified argument. If the supplied element is a
* TLV container (structure, array or path), the entire contents of the container will be copied.
*
* @note This method requires the supplied TVLReader object to be reading from a single, contiguous
* input buffer that contains the entirety of the underlying TLV encoding. Supplying a reader in any
* other mode has undefined behavior.
*
* @param[in] tag The TLV tag to be encoded with the container, or @p AnonymousTag() if
* the container should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] reader A reference to a TLVReader object identifying a pre-encoded TLV
* element whose type and value should be copied.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE
* If the supplied reader is not positioned on an element.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_TLV_UNDERRUN
* If the underlying TLV encoding associated with the supplied reader ended
* prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the supplied reader encountered an invalid or unsupported TLV element
* type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the supplied reader encountered a TLV tag in an invalid context,
* or if the supplied tag is invalid or inappropriate in the context in
* which the new container is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* GetNewBuffer() or FinalizeBuffer() functions, or by the GetNextBuffer()
* function associated with the reader object.
*
*/
CHIP_ERROR CopyElement(Tag tag, TLVReader & reader);
/**
* Begins encoding a new TLV container element.
*
* The StartContainer() method is used to write TLV container elements (structure, arrays or paths)
* to an encoding. The method takes the type and tag (if any) of the new container, and a reference
* to a TLVType value which will be used to save the current context of the writer while it is being
* used to write the container.
*
* Once the StartContainer() method returns, the application should use the current TLVWriter object to
* write the elements of the container. When finish, the application must call the EndContainer()
* method to finish the encoding of the container.
*
* @param[in] tag The TLV tag to be encoded with the container, or @p AnonymousTag() if
* the container should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] containerType The type of container to encode. Must be one of @p kTLVType_Structure,
* @p kTLVType_Array or @p kTLVType_List.
* @param[out] outerContainerType
* A reference to a TLVType value that will receive the context of the
* writer.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE
* If the value specified for containerType is incorrect.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR StartContainer(Tag tag, TLVType containerType, TLVType & outerContainerType);
/**
* Completes the encoding of a TLV container element.
*
* The EndContainer() method completes the encoding of a TLV container element and restores the state
* of a TLVWrite object after an earlier call to StartContainer(). For every call to StartContainer()
* applications must make a corresponding call to EndContainer(), passing the TLVType value returned
* by the StartContainer() call. When EndContainer() returns, the writer object can be used to write
* additional TLV elements that follow the container element.
*
* @note Any changes made to the configuration of the writer between the calls to StartContainer()
* and EndContainer() are NOT undone by the call to EndContainer(). For example, a change to the
* implicit profile id (@p ImplicitProfileId) will not be reversed when a container is ended. Thus
* it is the application's responsibility to adjust the configuration accordingly at the appropriate
* times.
*
* @param[in] outerContainerType
* The TLVType value that was returned by the StartContainer() method.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE
* If a corresponding StartContainer() call was not made.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR EndContainer(TLVType outerContainerType);
/**
* Initializes a new TLVWriter object for writing the members of a TLV container element.
*
* The OpenContainer() method is used to write TLV container elements (structure, arrays or paths)
* to an encoding. The method takes the type and tag (if any) of the new container, and a reference
* to a new writer object (the <em>container writer</em>) that will be initialized for the purpose
* of writing the container's elements. Applications write the members of the new container using
* the container writer and then call CloseContainer() to complete the container encoding.
*
* While the container writer is open, applications must not make calls on or otherwise alter the state
* of the parent writer.
*
* The container writer inherits various configuration properties from the parent writer. These are:
*
* @li The implicit profile id (ImplicitProfileId)
* @li The application data pointer (AppData)
* @li The GetNewBuffer and FinalizeBuffer function pointers
*
* @note The StartContainer() method can be used as an alternative to OpenContainer() to write a
* container element without initializing a new writer object.
*
* @param[in] tag The TLV tag to be encoded with the container, or @p AnonymousTag() if
* the container should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] containerType The type of container to encode. Must be one of @p kTLVType_Structure,
* @p kTLVType_Array or @p kTLVType_List.
* @param[out] containerWriter A reference to a TLVWriter object that will be initialized for
* writing the members of the new container element. Any data
* associated with the supplied object is overwritten.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE
* If the value specified for containerType is incorrect.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR OpenContainer(Tag tag, TLVType containerType, TLVWriter & containerWriter);
/**
* Completes the writing of a TLV container after a call to OpenContainer().
*
* The CloseContainer() method restores the state of a parent TLVWriter object after a call to
* OpenContainer(). For every call to OpenContainer() applications must make a corresponding
* call to CloseContainer(), passing a reference to the same container writer to both methods.
*
* When CloseContainer() returns, applications may continue to use the parent writer to write
* additional TLV elements that appear after the container element. At this point the supplied
* container writer should be considered 'de-initialized' and must not be used without
* re-initialization.
*
* @param[in] containerWriter A reference to the TLVWriter object that was supplied to the
* OpenContainer() method.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE
* If the supplied container writer is not in the correct state.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If another container writer has been opened on the supplied
* container writer and not yet closed.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If completing the encoding of the container would exceed the
* limit on the maximum number of bytes specified when the writer
* was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack
* of memory.
* @retval other Other CHIP or platform-specific errors returned by the
* configured TLVBackingStore.
*
*/
CHIP_ERROR CloseContainer(TLVWriter & containerWriter);
/**
* Encodes a TLV container element from a pre-encoded set of member elements
*
* The PutPreEncodedContainer() method encodes a new TLV container element (a structure, array or path)
* containing a set of member elements taken from a pre-encoded buffer. The input buffer is expected to
* contain zero or more full-encoded TLV elements, with tags that conform to the rules associated with
* the specified container type (e.g. structure members must have tags, while array members must not).
*
* The method encodes the entirety of the container element in one call. When PutPreEncodedContainer()
* returns, the writer object can be used to write additional TLV elements following the container element.
*
* @param[in] tag The TLV tag to be encoded with the container, or @p AnonymousTag() if
* the container should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] containerType The type of container to encode. Must be one of @p kTLVType_Structure,
* @p kTLVType_Array or @p kTLVType_List.
* @param[in] data A pointer to a buffer containing zero of more encoded TLV elements that
* will become the members of the new container.
* @param[in] dataLen The number of bytes in the @p data buffer.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE
* If the value specified for containerType is incorrect.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the specified tag value is invalid or inappropriate in the context
* in which the value is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR PutPreEncodedContainer(Tag tag, TLVType containerType, const uint8_t * data, uint32_t dataLen);
/**
* Copies a TLV container element from TLVReader object
*
* The CopyContainer() encodes a new TLV container element by copying a pre-encoded container element
* located at the current position of a TLVReader object. The method writes the entirety of the new
* container element in one call, copying the container's type, tag and elements from the source
* encoding. When the method returns, the writer object can be used to write additional TLV elements
* following the container element.
*
* @note This method requires the supplied TVLReader object to be reading from a single, contiguous
* input buffer that contains the entirety of the underlying TLV encoding.
*
* @param[in] container A reference to a TLVReader object identifying the pre-encoded TLV
* container to be copied.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INVALID_ARGUMENT
* If the supplied reader uses a TLVBackingStore rather than a simple buffer.
* @retval #CHIP_ERROR_INCORRECT_STATE
* If the supplied reader is not positioned on a container element.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_TLV_UNDERRUN
* If the underlying TLV encoding associated with the supplied reader ended
* prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the supplied reader encountered an invalid or unsupported TLV element
* type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the supplied reader encountered a TLV tag in an invalid context,
* or if the tag associated with the source container is invalid or
* inappropriate in the context in which the new container is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR CopyContainer(TLVReader & container);
/**
* Encodes a TLV container element from a pre-encoded set of member elements
*
* The CopyContainer() method encodes a new TLV container element (a structure, array or path)
* containing a set of member elements taken from a TLVReader object. When the method is called, the
* supplied reader object is expected to be positioned on a TLV container element. The newly encoded
* container will have the same type and members as the input container. The tag for the new
* container is specified as an input parameter.
*
* When the method returns, the writer object can be used to write additional TLV elements following
* the container element.
*
* @note This method requires the supplied TVLReader object to be reading from a single, contiguous
* input buffer that contains the entirety of the underlying TLV encoding.
*
* @param[in] tag The TLV tag to be encoded with the container, or @p AnonymousTag() if
* the container should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] container A reference to a TLVReader object identifying a pre-encoded TLV
* container whose type and members should be copied.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INVALID_ARGUMENT
* If the supplied reader uses a TLVBackingStore rather than a simple buffer.
* @retval #CHIP_ERROR_INCORRECT_STATE
* If the supplied reader is not positioned on a container element.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_TLV_UNDERRUN
* If the underlying TLV encoding associated with the supplied reader ended
* prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the supplied reader encountered an invalid or unsupported TLV element
* type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the supplied reader encountered a TLV tag in an invalid context,
* or if the supplied tag is invalid or inappropriate in the context in
* which the new container is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR CopyContainer(Tag tag, TLVReader & container);
/**
* Encodes a TLV container element that contains member elements from a pre-encoded container
*
* The CopyContainer() method encodes a new TLV container element (a structure, array or path)
* containing a set of member elements taken from the contents of a supplied pre-encoded container.
* When the method is called, data in the supplied input buffer is parsed as a TLV container element
* an a new container is written that has the same type and members as the input container. The tag
* for the new container is specified as an input parameter.
*
* When the method returns, the writer object can be used to write additional TLV elements following
* the container element.
*
* @param[in] tag The TLV tag to be encoded with the container, or @p AnonymousTag() if
* the container should be encoded without a tag. Tag values should be
* constructed with one of the tag definition functions ProfileTag(),
* ContextTag() or CommonTag().
* @param[in] encodedContainer A buffer containing a pre-encoded TLV container whose type and members
* should be copied.
* @param[in] encodedContainerLen The length in bytes of the pre-encoded container.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_CONTAINER_OPEN
* If a container writer has been opened on the current writer and not
* yet closed.
* @retval #CHIP_ERROR_TLV_UNDERRUN
* If the encoded container ended prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the encoded container contained an invalid or unsupported TLV element type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG
* If the encoded container contained a TLV tag in an invalid context,
* or if the supplied tag is invalid or inappropriate in the context in
* which the new container is being written.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL
* If writing the value would exceed the limit on the maximum number of
* bytes specified when the writer was initialized.
* @retval #CHIP_ERROR_NO_MEMORY
* If an attempt to allocate an output buffer failed due to lack of
* memory.
* @retval other Other CHIP or platform-specific errors returned by the configured
* TLVBackingStore.
*
*/
CHIP_ERROR CopyContainer(Tag tag, const uint8_t * encodedContainer, uint16_t encodedContainerLen);
/**
* Returns the type of container within which the TLVWriter is currently writing.
*
* The GetContainerType() method returns the type of the TLV container within which the TLVWriter
* is currently writing. If the TLVWriter is not writing elements within a container (i.e. if writing
* at the outer-most level of an encoding) the method returns kTLVType_NotSpecified.
*
* @return The TLVType of the current container, or kTLVType_NotSpecified if the TLVWriter is not
* writing elements within a container.
*/
TLVType GetContainerType() const { return mContainerType; }
/**
* Returns the total number of bytes written since the writer was initialized.
*
* @return Total number of bytes written since the writer was initialized.
*/
uint32_t GetLengthWritten() const { return mLenWritten; }
/**
* Returns the total remaining number of bytes for current tlv writer
*
* @return the total remaining number of bytes.
*/
uint32_t GetRemainingFreeLength() const { return mRemainingLen; }
/**
* The profile id of tags that should be encoded in implicit form.
*
* When a writer is asked to encode a new element, if the profile id of the tag associated with the
* new element matches the value of the @p ImplicitProfileId member, the writer will encode the tag
* in implicit form, omitting the profile id in the process.
*
* By default, the @p ImplicitProfileId property is set to kProfileIdNotSpecified, which instructs
* the writer not to emit implicitly encoded tags. Applications can set @p ImplicitProfileId at any
* time to enable encoding tags in implicit form starting at the current point in the encoding. The
* appropriate profile id to set is usually dependent on the context of the application or protocol
* being spoken.
*
* @note The value of the @p ImplicitProfileId member affects the encoding of profile-specific
* tags only; the encoding of context-specific tags is unchanged.
*/
uint32_t ImplicitProfileId;
/**
* A pointer field that can be used for application-specific data.
*/
void * AppData;
protected:
TLVBackingStore * mBackingStore;
uint8_t * mBufStart;
uint8_t * mWritePoint;
uint32_t mRemainingLen;
uint32_t mLenWritten;
uint32_t mMaxLen;
uint32_t mReservedSize;
TLVType mContainerType;
private:
bool mContainerOpen;
bool mCloseContainerReserved;
protected:
bool IsContainerOpen() const { return mContainerOpen; }
void SetContainerOpen(bool aContainerOpen) { mContainerOpen = aContainerOpen; }
enum
{
kEndOfContainerMarkerSize = 1, /**< Size of the EndOfContainer marker, used in reserving space. */
};
/**
* @brief
* Determine whether the container should reserve space for the
* CloseContainer symbol at the point of starting / opening the
* container.
*/
bool IsCloseContainerReserved() const { return mCloseContainerReserved; }
/**
* @brief
* Set whether the container should reserve the space for the
* CloseContainer symbol at the point of starting / opening the
* container.
*/
void SetCloseContainerReserved(bool aCloseContainerReserved) { mCloseContainerReserved = aCloseContainerReserved; }
#if CONFIG_HAVE_VCBPRINTF
static void CHIPTLVWriterPutcharCB(uint8_t c, void * appState);
#endif
CHIP_ERROR WriteElementHead(TLVElementType elemType, Tag tag, uint64_t lenOrVal);
CHIP_ERROR WriteElementWithData(TLVType type, Tag tag, const uint8_t * data, uint32_t dataLen);
CHIP_ERROR WriteData(const uint8_t * p, uint32_t len);
};
/*
* A TLVWriter that is backed by a scoped memory buffer that is owned by the writer.
*/
class ScopedBufferTLVWriter : public TLVWriter
{
public:
/*
* Construct and initialize the writer by taking ownership of the provided scoped buffer.
*/
ScopedBufferTLVWriter(Platform::ScopedMemoryBuffer<uint8_t> && buffer, size_t dataLen)
{
mBuffer = std::move(buffer);
Init(mBuffer.Get(), dataLen);
}
/*
* Finalize the writer and take back the buffer owned by the writer. This transfers its
* ownership to the provided buffer reference. This also re-initializes the writer with
* a null buffer to prevent further inadvertent use of the writer.
*/
CHIP_ERROR Finalize(Platform::ScopedMemoryBuffer<uint8_t> & buffer)
{
ReturnErrorOnFailure(TLVWriter::Finalize());
buffer = std::move(mBuffer);
Init(nullptr, 0);
return CHIP_NO_ERROR;
}
private:
Platform::ScopedMemoryBuffer<uint8_t> mBuffer;
};
/**
* Provides a unified Reader/Writer interface for editing/adding/deleting elements in TLV encoding.
*
* The TLVUpdater is a union of the TLVReader and TLVWriter objects and provides interface methods
* for editing/deleting data in an encoding as well as adding new elements to the TLV encoding. The
* TLVUpdater object essentially acts like two cursors, one for reading existing encoding and
* another for writing (either for copying over existing data or writing new data).
*
* Semantically, the TLVUpdater object functions like a union of the TLVReader and TLVWriter. The
* TLVUpdater methods have more or less similar meanings as similarly named counterparts in
* TLVReader/TLVWriter. Where there are differences in the semantics, the differences are clearly
* documented in the function's comment section in CHIPTLVUpdater.cpp.
*
* One particularly important note about the TLVUpdater's PutBytes() and PutString() methods is that
* it can leave the encoding in a corrupt state with only the element header written when an
* overflow occurs. Applications can call GetRemainingFreeLength() to make sure there is
* @em approximately enough free space to write the encoding. Note that GetRemainingFreeLength()
* only tells you the available free bytes and there is @em no way for the application to know the
* length of encoded data that gets written. In the event of an overflow, both PutBytes() and
* PutString() will return CHIP_ERROR_BUFFER_TOO_SMALL to the caller.
*
* Also, note that Next() method is overloaded to both skip the current element and also advance the
* internal reader to the next element. Because skipping already encoded elements requires changing
* the internal writer's free space state variables to account for the new freed space (made
* available by skipping), the application is expected to call Next() on the updater after a Get()
* method whose value it doesn't wish to write back (which is equivalent to skipping the current
* element).
*
* @note The application is expected to use the TLVUpdater object atomically from the time it calls
* Init() till it calls Finalize(). The same buffer should NOT be used with other TLVWriter objects.
*
* @note The TLVUpdater currently only supports single static buffers. TLVBackingStore is NOT supported.
*/
class DLL_EXPORT TLVUpdater
{
public:
/**
* Initialize a TLVUpdater object to edit a single input buffer.
*
* On calling this method, the TLV data in the buffer is moved to the end of the
* buffer and a private TLVReader object is initialized on this relocated
* buffer. A private TLVWriter object is also initialized on the free space that
* is now available at the beginning. Applications can use the TLVUpdater object
* to parse the TLV data and modify/delete existing elements or add new elements
* to the encoding.
*
* @param[in] buf A pointer to a buffer containing the TLV data to be edited.
* @param[in] dataLen The length of the TLV data in the buffer.
* @param[in] maxLen The total length of the buffer.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INVALID_ARGUMENT If the buffer address is invalid.
* @retval #CHIP_ERROR_BUFFER_TOO_SMALL If the buffer is too small.
*
*/
CHIP_ERROR Init(uint8_t * buf, uint32_t dataLen, uint32_t maxLen);
/**
* Initialize a TLVUpdater object using a TLVReader.
*
* On calling this method, TLV data in the buffer pointed to by the TLVReader
* is moved from the current read point to the end of the buffer. A new
* private TLVReader object is initialized to read from this new location, while
* a new private TLVWriter object is initialized to write to the freed up buffer
* space.
*
* Note that if the TLVReader is already positioned "on" an element, it is first
* backed-off to the start of that element. Also note that this backing off
* works well with container elements, i.e., if the TLVReader was already used
* to call EnterContainer(), then there is nothing to back-off. But if the
* TLVReader was positioned on the container element and EnterContainer() was
* not yet called, then the TLVReader object is backed-off to the start of the
* container head.
*
* The input TLVReader object will be destroyed before returning and the
* application must not make use of the same on return.
*
* @param[in,out] aReader Reference to a TLVReader object that will be
* destroyed before returning.
* @param[in] freeLen The length of free space (in bytes) available
* in the pre-encoded data buffer.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INVALID_ARGUMENT If the buffer address is invalid.
* @retval #CHIP_ERROR_NOT_IMPLEMENTED If reader was initialized on a chain
* of buffers.
*/
CHIP_ERROR Init(TLVReader & aReader, uint32_t freeLen);
CHIP_ERROR Finalize() { return mUpdaterWriter.Finalize(); }
// Common methods
/**
* Set the Implicit Profile ID for the TLVUpdater object.
*
* This method sets the implicit profile ID for the TLVUpdater object. When the
* updater is asked to encode a new element, if the profile ID of the tag
* associated with the new element matches the value of the @p profileId, the
* updater will encode the tag in implicit form, thereby omitting the profile ID
* in the process.
*
* @param[in] profileId The profile id of tags that should be encoded in
* implicit form.
*/
void SetImplicitProfileId(uint32_t profileId);
uint32_t GetImplicitProfileId() const { return mUpdaterReader.ImplicitProfileId; }
/**
* Copies the current element from input TLV to output TLV.
*
* The Move() method copies the current element on which the TLVUpdater's reader
* is positioned on, to the TLVUpdater's writer. The application should call
* Next() and position the TLVUpdater's reader on an element before calling this
* method. Just like the TLVReader::Next() method, if the reader is positioned
* on a container element at the time of the call, all the members of the
* container will be copied. If the reader is not positioned on any element,
* nothing changes on calling this method.
*
* @retval #CHIP_NO_ERROR If the TLVUpdater reader was
* successfully positioned on a new
* element.
* @retval #CHIP_END_OF_TLV If the TLVUpdater's reader is pointing
* to end of container.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the TLVIpdater's reader is not
* positioned on a valid TLV element.
* @retval other Returns other error codes returned by
* TLVReader::Skip() method.
*
*/
CHIP_ERROR Move();
/**
* Move everything from the TLVUpdater's current read point till end of input
* TLV buffer over to output.
*
* This method supports moving everything from the TLVUpdater's current read
* point till the end of the reader buffer over to the TLVUpdater's writer.
*
* @note This method can be called with the TLVUpdater's reader positioned
* anywhere within the input TLV. The reader can also be positioned under
* multiple levels of nested containers and this method will still work.
*
* @note This method also changes the state of the TLVUpdater object to a state
* it would be in if the application had painstakingly parsed each element from
* the current read point till the end of the input encoding and copied them to
* the output TLV.
*/
void MoveUntilEnd();
/**
* Prepares a TLVUpdater object for reading elements of a container. It also
* encodes a start of container object in the output TLV.
*
* The EnterContainer() method prepares the current TLVUpdater object to begin
* reading the member elements of a TLV container (a structure, array or path).
* For every call to EnterContainer() applications must make a corresponding
* call to ExitContainer().
*
* When EnterContainer() is called the TLVUpdater's reader must be positioned on
* the container element. The method takes as an argument a reference to a
* TLVType value which will be used to save the context of the updater while it
* is reading the container.
*
* When the EnterContainer() method returns, the updater is positioned
* immediately @em before the first member of the container. Repeatedly calling
* Next() will advance the updater through the members of the collection until
* the end is reached, at which point the updater will return CHIP_END_OF_TLV.
*
* Once the application has finished reading a container it can continue reading
* the elements after the container by calling the ExitContainer() method.
*
* @note This method implicitly encodes a start of container element in the
* output TLV buffer.
*
* @param[out] outerContainerType A reference to a TLVType value that will
* receive the context of the updater.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_INCORRECT_STATE If the TLVUpdater reader is not
* positioned on a container element.
* @retval other Any other CHIP or platform error code
* returned by TLVWriter::StartContainer()
* or TLVReader::EnterContainer().
*
*/
CHIP_ERROR EnterContainer(TLVType & outerContainerType);
/**
* Completes the reading of a TLV container element and encodes an end of TLV
* element in the output TLV.
*
* The ExitContainer() method restores the state of a TLVUpdater object after a
* call to EnterContainer(). For every call to EnterContainer() applications
* must make a corresponding call to ExitContainer(), passing the context value
* returned by the EnterContainer() method.
*
* When ExitContainer() returns, the TLVUpdater reader is positioned immediately
* before the first element that follows the container in the input TLV. From
* this point applications can call Next() to advance through any remaining
* elements.
*
* Once EnterContainer() has been called, applications can call ExitContainer()
* on the updater at any point in time, regardless of whether all elements in
* the underlying container have been read. Also, note that calling
* ExitContainer() before reading all the elements in the container, will result
* in the updated container getting truncated in the output TLV.
*
* @note Any changes made to the configuration of the updater between the calls
* to EnterContainer() and ExitContainer() are NOT undone by the call to
* ExitContainer(). For example, a change to the implicit profile id
* (@p ImplicitProfileId) will not be reversed when a container is exited. Thus
* it is the application's responsibility to adjust the configuration
* accordingly at the appropriate times.
*
* @param[in] outerContainerType The TLVType value that was returned by
* the EnterContainer() method.
*
* @retval #CHIP_NO_ERROR If the method succeeded.
* @retval #CHIP_ERROR_TLV_UNDERRUN If the underlying TLV encoding ended
* prematurely.
* @retval #CHIP_ERROR_INVALID_TLV_ELEMENT
* If the updater encountered an invalid or
* unsupported TLV element type.
* @retval #CHIP_ERROR_INVALID_TLV_TAG If the updater encountered a TLV tag in
* an invalid context.
* @retval other Any other CHIP or platform error code
* returned by TLVWriter::EndContainer() or
* TLVReader::ExitContainer().
*
*/
CHIP_ERROR ExitContainer(TLVType outerContainerType);
void GetReader(TLVReader & containerReader) { containerReader = mUpdaterReader; }
// Reader methods
/**
* Skip the current element and advance the TLVUpdater object to the next
* element in the input TLV.
*
* The Next() method skips the current element in the input TLV and advances the
* TLVUpdater's reader to the next element that resides in the same containment
* context. In particular, if the reader is positioned at the outer most level
* of a TLV encoding, calling Next() will advance it to the next, top most
* element. If the reader is positioned within a TLV container element (a
* structure, array or path), calling Next() will advance it to the next member
* element of the container.
*
* Since Next() constrains reader motion to the current containment context,
* calling Next() when the reader is positioned on a container element will
* advance @em over the container, skipping its member elements (and the members
* of any nested containers) until it reaches the first element after the
* container.
*
* When there are no further elements within a particular containment context
* the Next() method will return a #CHIP_END_OF_TLV error and the position of
* the reader will remain unchanged.
*
* @note The Next() method implicitly skips the current element. Hence, the
* TLVUpdater's private writer state variables will be adjusted to account for
* the new freed space (made available by skipping). This means that the
* application is expected to call Next() on the TLVUpdater object after a Get()
* whose value the application does @em not write back (which from the
* TLVUpdater's view is equivalent to skipping that element).
*
* @note Applications are also expected to call Next() when they are at the end
* of a container, and want to add new elements there. This is particularly
* important in situations where there is a fixed schema. Applications that have
* fixed schemas and know where the container end is cannot just add new
* elements at the end, because the TLVUpdater writer's state will not reflect
* the correct free space available for the Put() operation. Hence, applications
* must call Next() (and possibly also test for CHIP_END_OF_TLV) before adding
* elements at the end of a container.
*
* @retval #CHIP_NO_ERROR If the TLVUpdater reader was
* successfully positioned on a new
* element.
* @retval other Returns the CHIP or platform error
* codes returned by the TLVReader::Skip()
* and TLVReader::Next() method.
*
*/
CHIP_ERROR Next();
CHIP_ERROR Get(bool & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(int8_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(int16_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(int32_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(int64_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(uint8_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(uint16_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(uint32_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(uint64_t & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(float & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(double & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(ByteSpan & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR Get(CharSpan & v) { return mUpdaterReader.Get(v); }
CHIP_ERROR GetBytes(uint8_t * buf, uint32_t bufSize) { return mUpdaterReader.GetBytes(buf, bufSize); }
CHIP_ERROR DupBytes(uint8_t *& buf, uint32_t & dataLen) { return mUpdaterReader.DupBytes(buf, dataLen); }
CHIP_ERROR GetString(char * buf, uint32_t bufSize) { return mUpdaterReader.GetString(buf, bufSize); }
CHIP_ERROR DupString(char *& buf) { return mUpdaterReader.DupString(buf); }
TLVType GetType() const { return mUpdaterReader.GetType(); }
Tag GetTag() const { return mUpdaterReader.GetTag(); }
uint32_t GetLength() const { return mUpdaterReader.GetLength(); }
CHIP_ERROR GetDataPtr(const uint8_t *& data) { return mUpdaterReader.GetDataPtr(data); }
CHIP_ERROR VerifyEndOfContainer() { return mUpdaterReader.VerifyEndOfContainer(); }
TLVType GetContainerType() const { return mUpdaterReader.GetContainerType(); }
uint32_t GetLengthRead() const { return mUpdaterReader.GetLengthRead(); }
uint32_t GetRemainingLength() const { return mUpdaterReader.GetRemainingLength(); }
// Writer methods
CHIP_ERROR Put(Tag tag, int8_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, int16_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, int32_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, int64_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, uint8_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, uint16_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, uint32_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, uint64_t v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, int8_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, int16_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, int32_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, int64_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, uint8_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, uint16_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, uint32_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, uint64_t v, bool preserveSize) { return mUpdaterWriter.Put(tag, v, preserveSize); }
CHIP_ERROR Put(Tag tag, float v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR Put(Tag tag, double v) { return mUpdaterWriter.Put(tag, v); }
CHIP_ERROR PutBoolean(Tag tag, bool v) { return mUpdaterWriter.PutBoolean(tag, v); }
CHIP_ERROR PutNull(Tag tag) { return mUpdaterWriter.PutNull(tag); }
CHIP_ERROR PutBytes(Tag tag, const uint8_t * buf, uint32_t len) { return mUpdaterWriter.PutBytes(tag, buf, len); }
CHIP_ERROR PutString(Tag tag, const char * buf) { return mUpdaterWriter.PutString(tag, buf); }
CHIP_ERROR PutString(Tag tag, const char * buf, uint32_t len) { return mUpdaterWriter.PutString(tag, buf, len); }
CHIP_ERROR CopyElement(TLVReader & reader) { return mUpdaterWriter.CopyElement(reader); }
CHIP_ERROR CopyElement(Tag tag, TLVReader & reader) { return mUpdaterWriter.CopyElement(tag, reader); }
CHIP_ERROR StartContainer(Tag tag, TLVType containerType, TLVType & outerContainerType)
{
return mUpdaterWriter.StartContainer(tag, containerType, outerContainerType);
}
CHIP_ERROR EndContainer(TLVType outerContainerType) { return mUpdaterWriter.EndContainer(outerContainerType); }
uint32_t GetLengthWritten() { return mUpdaterWriter.GetLengthWritten(); }
uint32_t GetRemainingFreeLength() const { return mUpdaterWriter.mRemainingLen; }
private:
void AdjustInternalWriterFreeSpace();
TLVWriter mUpdaterWriter;
TLVReader mUpdaterReader;
const uint8_t * mElementStartAddr;
};
/**
* Provides an interface for TLVReader or TLVWriter to use memory other than a simple contiguous buffer.
*/
class DLL_EXPORT TLVBackingStore
{
public:
virtual ~TLVBackingStore() {}
/**
* A function to provide a backing store's initial start position and data length to a reader.
*
* @param[in] reader A reference to the TLVReader object that is requesting input data.
* @param[out] bufStart A reference to a data pointer. On exit, bufStart is expected to point
* to the first byte of TLV data to be parsed.
* @param[out] bufLen A reference to an unsigned integer that the function must set to
* the number of TLV data bytes being returned. If the end of the
* input TLV data has been reached, the function should set this value
* to 0.
*
* @retval #CHIP_NO_ERROR If the function successfully produced TLV data.
* @retval other Other CHIP or platform-specific error codes indicating that an error
* occurred preventing the function from producing the requested data.
*/
virtual CHIP_ERROR OnInit(TLVReader & reader, const uint8_t *& bufStart, uint32_t & bufLen) = 0;
/**
* A function that can be used to retrieve additional TLV data to be parsed.
*
* When called, the function is expected to produce additional data for the reader to parse or signal
* the reader that no more data is available.
*
* @param[in] reader A reference to the TLVReader object that is requesting input data.
* @param[in,out] bufStart A reference to a data pointer. On entry to the function, @p bufStart
* points to one byte beyond the last TLV data byte consumed by the
* reader. On exit, bufStart is expected to point to the first byte
* of new TLV data to be parsed. The new pointer value can be within
* the same buffer as the previously consumed data, or it can point
* to an entirely new buffer.
* @param[out] bufLen A reference to an unsigned integer that the function must set to
* the number of TLV data bytes being returned. If the end of the
* input TLV data has been reached, the function should set this value
* to 0.
*
* @retval #CHIP_NO_ERROR If the function successfully produced more TLV data, or the end of
* the input data was reached (@p bufLen should be set to 0 in this case).
* @retval other Other CHIP or platform-specific error codes indicating that an error
* occurred preventing the function from producing the requested data.
*/
virtual CHIP_ERROR GetNextBuffer(TLVReader & reader, const uint8_t *& bufStart, uint32_t & bufLen) = 0;
/**
* A function to provide a backing store's initial start position and data length to a writer.
*
* @param[in] writer A reference to the TLVWriter object that is requesting new buffer
* space.
* @param[out] bufStart A reference to a data pointer. On exit, @p bufStart is expected to
* point to the beginning of the new output buffer.
* @param[out] bufLen A reference to an unsigned integer. On exit, @p bufLen is expected
* to contain the maximum number of bytes that can be written to the
* new output buffer.
*
* @retval #CHIP_NO_ERROR If the function was able to supply buffer space for the writer.
* @retval other Other CHIP or platform-specific error codes indicating that an error
* occurred preventing the function from producing buffer space.
*/
virtual CHIP_ERROR OnInit(TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen) = 0;
/**
* A function that supplies new output buffer space to a TLVWriter.
*
* The function is expected to return a pointer to a memory location where new data should be written,
* along with an associated maximum length. The function can supply write space either by allocating
* a new buffer to hold the data or by clearing out previously written data from an existing buffer.
*
* @param[in] writer A reference to the TLVWriter object that is requesting new buffer
* space.
* @param[in,out] bufStart A reference to a data pointer. On entry to the function, @p bufStart
* points the beginning of the current output buffer. On exit, @p bufStart
* is expected to point to the beginning of the new output buffer.
* The new pointer value can be the same as the previous value (e.g.
* if the function copied the existing data elsewhere), or it can point
* to an entirely new location.
* @param[in,out] bufLen A reference to an unsigned integer. On entry to the function,
* @p bufLen contains the number of byte of @em unused space in the
* current buffer. On exit, @p bufLen is expected to contain the maximum
* number of bytes that can be written to the new output buffer.
*
* @retval #CHIP_NO_ERROR If the function was able to supply more buffer space for the writer.
* @retval other Other CHIP or platform-specific error codes indicating that an error
* occurred preventing the function from producing additional buffer
* space.
*/
virtual CHIP_ERROR GetNewBuffer(TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen) = 0;
/**
* A function used to perform finalization of the output from a TLVWriter object.
*
* Functions of this type are called when a TLVWriter's Finalize() method is called. The function is
* expected to perform any necessary clean-up or finalization related to consuming the output of the
* writer object. Examples of this include such things as recording the final length of the encoding,
* or closing a file descriptor.
*
* @param[in] writer A reference to the TLVWriter object that is being finalized.
* @param[in,out] bufStart A pointer to the beginning of the current (and final) output buffer.
* @param[in,out] bufLen The number of bytes contained in the buffer pointed to by @p bufStart.
*
* @retval #CHIP_NO_ERROR If finalization was successful.
* @retval other Other CHIP or platform-specific error codes indicating that an error
* occurred during finalization.
*
*/
virtual CHIP_ERROR FinalizeBuffer(TLVWriter & writer, uint8_t * bufStart, uint32_t bufLen) = 0;
};
constexpr size_t EstimateStructOverhead()
{
// The struct itself has a control byte and an end-of-struct marker.
return 2;
}
template <typename... FieldSizes>
constexpr size_t EstimateStructOverhead(size_t firstFieldSize, FieldSizes... otherFields)
{
// Estimate 4 bytes of overhead per field. This can happen for a large
// octet string field: 1 byte control, 1 byte context tag, 2 bytes
// length.
return firstFieldSize + 4u + EstimateStructOverhead(otherFields...);
}
} // namespace TLV
} // namespace chip