blob: ae9eeb40c46163913cfc14ffa065b092c207a1cf [file]
// Copyright 2026 Google LLC
//
// 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
//
// https://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 "jumbf/test_utils.h"
#include <cstdint>
#include <cstring>
#include <optional>
#include <string>
#include "absl/log/check.h"
#include "absl/strings/cord.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "jumbf/constants.h"
#include "riegeli/endian/endian_writing.h"
#include "uuid/uuid.h"
namespace jumbf {
std::string WrapBox(absl::string_view content, uint32_t tbox) {
const uint32_t lbox = content.length() + /*lbox*/ 4 + /*tbox*/ 4;
std::string serialized(lbox, '\0');
char* cursor = serialized.data();
riegeli::WriteBigEndian<uint32_t>(lbox, cursor);
cursor += sizeof(uint32_t);
riegeli::WriteBigEndian<uint32_t>(tbox, cursor);
cursor += sizeof(uint32_t);
// This is safe because the length of `serialized` has been calculated above
// to always have enough room for `content`.
memcpy(cursor, content.data(), content.length());
return serialized;
}
std::string WrapUndeterminedLengthBox(absl::string_view content,
uint32_t tbox) {
const uint32_t box_length = content.length() + /*lbox*/ 4 + /*tbox*/ 4;
std::string serialized(box_length, '\0');
char* cursor = serialized.data();
// LBox value
riegeli::WriteBigEndian<uint32_t>(0, cursor);
cursor += sizeof(uint32_t);
riegeli::WriteBigEndian<uint32_t>(tbox, cursor);
cursor += sizeof(uint32_t);
// This is safe because the length of `serialized` has been calculated above
// to always have enough room for `content`.
memcpy(cursor, content.data(), content.length());
return serialized;
}
void SerializeUuid(char** dest, credentio::Uuid uuid) {
const std::string bytes = uuid.ToProtoBytes();
if (bytes.size() == 16) {
memcpy(*dest, bytes.data(), 16);
} else {
memset(*dest, 0, 16);
}
*dest += 16;
}
std::string EncodeDescriptionBox(credentio::Uuid uuid,
std::optional<absl::string_view> label,
bool requestable) {
if (label.has_value()) {
CHECK(!absl::StrContains(*label, '\0'));
const size_t description_content_length = /*uuid*/ 16 + /*toggles*/ 1 +
label->size() +
/*label NUL terminator*/ 1;
std::string description_content(description_content_length, '\0');
char* content_cursor = description_content.data();
jumbf::SerializeUuid(&content_cursor, uuid);
uint8_t toggles = kDescriptionToggleLabelPresent;
if (requestable) {
toggles |= kDescriptionToggleRequestable;
}
riegeli::WriteBigEndian<uint8_t>(toggles, content_cursor);
content_cursor += sizeof(uint8_t);
memcpy(content_cursor, label->data(), label->size());
content_cursor += label->size();
*content_cursor++ = '\0';
return WrapBox(description_content, kDescriptionBoxType);
}
const size_t description_content_length = /*uuid*/ 16 + /*toggles*/ 1 +
/*label NUL terminator*/ 1;
std::string description_content(description_content_length, '\0');
char* content_cursor = description_content.data();
jumbf::SerializeUuid(&content_cursor, uuid);
uint8_t toggles = kDescriptionToggleEmpty;
riegeli::WriteBigEndian<uint8_t>(toggles, content_cursor);
content_cursor += sizeof(uint8_t);
*content_cursor++ = '\0';
return WrapBox(description_content, kDescriptionBoxType);
}
std::string EncodeCborBox(absl::string_view contents) {
return WrapBox(contents, kCborBoxType);
}
std::string EncodeSuperBox(credentio::Uuid uuid,
std::optional<absl::string_view> label,
absl::Span<const absl::string_view> contents,
bool requestable) {
return jumbf::WrapBox(
absl::StrCat(EncodeDescriptionBox(uuid, label, requestable),
absl::StrJoin(contents, "")),
jumbf::kSuperBoxType);
}
absl::Cord CordFromConstexpr(absl::string_view data) {
return absl::MakeCordFromExternal(data, [](absl::string_view data) {});
}
} // namespace jumbf