blob: 8337acd44a8c07b42f5b8c2fa06debfc62042457 [file] [log] [blame] [edit]
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#include "tlv.h"
#include <endian.h>
#include <cstring>
#include <format>
#include <limits>
#include <stdexcept>
namespace debug_token::tlv_encoder
{
Item::Item(uint16_t type, const std::vector<uint8_t>& input)
{
if (input.size() > std::numeric_limits<uint16_t>::max())
{
throw std::runtime_error(std::format(
"TLV item value size is greater than the maximum value size - size: {}",
input.size()));
}
data = std::vector<uint8_t>();
data.reserve(sizeof(ItemHeader) + input.size());
auto header = std::make_shared<ItemHeader>();
header->type = htole16(type);
header->size = htole16(input.size());
data.resize(sizeof(ItemHeader));
std::memcpy(data.data(), header.get(), sizeof(ItemHeader));
data.insert(data.end(), input.begin(), input.end());
}
size_t Item::getTotalSize() const
{
return data.size();
}
const std::vector<uint8_t>& Item::getValue() const
{
return data;
}
Structure::Structure()
{
header = std::make_shared<StructureHeader>();
std::memcpy(header->identifier, TLV_IDENTIFIER, sizeof(TLV_IDENTIFIER));
header->versionMajor = htole16(1);
header->versionMinor = htole16(0);
header->size = htole32(0);
std::memset(header->reserved, 0, sizeof(header->reserved));
}
void Structure::setVersion(uint16_t major, uint16_t minor)
{
header->versionMajor = htole16(major);
header->versionMinor = htole16(minor);
}
void Structure::add(uint16_t type, const std::vector<uint8_t>& input)
{
if (data.contains(type))
{
throw std::runtime_error(
std::format("Duplicate TLV data type - type: {}", type));
}
try
{
data.emplace(type, Item(type, input));
}
catch (const std::runtime_error& e)
{
throw std::runtime_error(std::format(
"Failed to add TLV data - type: {}, error: {}", type, e.what()));
}
}
void Structure::add(uint16_t type, const std::vector<uint32_t>& input)
{
if (data.contains(type))
{
throw std::runtime_error(
std::format("Duplicate TLV data type - type: {}", type));
}
try
{
std::vector<uint8_t> inputU8;
inputU8.reserve(input.size() * sizeof(uint32_t));
for (const auto& value : input)
{
uint32_t leValue = htole32(value);
inputU8.insert(inputU8.end(), reinterpret_cast<uint8_t*>(&leValue),
reinterpret_cast<uint8_t*>(&leValue) +
sizeof(leValue));
}
data.emplace(type, Item(type, inputU8));
}
catch (const std::runtime_error& e)
{
throw std::runtime_error(std::format(
"Failed to add TLV data - type: {}, error: {}", type, e.what()));
}
}
void Structure::add(uint16_t type, uint8_t value)
{
add(type, std::vector<uint8_t>{value});
}
void Structure::add(uint16_t type, uint16_t value)
{
uint16_t leValue = htole16(value);
add(type, std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&leValue),
reinterpret_cast<uint8_t*>(&leValue) +
sizeof(leValue)));
}
void Structure::add(uint16_t type, uint32_t value)
{
uint32_t leValue = htole32(value);
add(type, std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&leValue),
reinterpret_cast<uint8_t*>(&leValue) +
sizeof(leValue)));
}
std::vector<uint8_t> Structure::encode()
{
uint64_t totalSize = 0;
for (const auto& [_, item] : data)
{
totalSize += item.getTotalSize();
if (totalSize > std::numeric_limits<uint32_t>::max())
{
throw std::overflow_error("TLV structure size exceeds max value");
}
}
header->size = static_cast<uint32_t>(totalSize);
std::vector<uint8_t> result;
result.reserve(sizeof(StructureHeader) + header->size);
result.resize(sizeof(StructureHeader));
header->size = htole32(header->size);
std::memcpy(result.data(), header.get(), sizeof(StructureHeader));
for (const auto& [type, value] : data)
{
result.insert(result.end(), value.getValue().begin(),
value.getValue().end());
}
return result;
}
} // namespace debug_token::tlv_encoder