| // 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 |