| // 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/internal/encode.h" |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <limits> |
| #include <utility> |
| |
| #include "absl/log/check.h" |
| #include "absl/status/status.h" |
| #include "absl/status/status_macros.h" |
| #include "absl/strings/cord.h" |
| #include "jumbf/constants.h" |
| #include "jumbf/encode_params.h" |
| #include "jumbf/internal/serialization_utils.h" |
| #include "riegeli/base/types.h" |
| #include "riegeli/bytes/backward_writer.h" |
| #include "uuid/uuid.h" |
| |
| namespace jumbf { |
| |
| using ::jumbf_internal::WriteInteger; |
| using ::jumbf_internal::WriteNulTerminated; |
| using ::jumbf_internal::WritePadding; |
| using ::jumbf_internal::WriteRaw; |
| |
| static_assert(std::numeric_limits<uint64_t>::max() >= |
| std::numeric_limits<size_t>::max(), |
| "This library converts from `size_t` to `uint64_t` when writing " |
| "XLBox values."); |
| |
| absl::Status EncodePaddingBox(uint64_t padding_size, |
| riegeli::BackwardWriter* writer) { |
| ABSL_RETURN_IF_ERROR(WritePadding(padding_size, writer)); |
| return EncodeBoxHeader(padding_size, kPaddingBoxType, writer); |
| } |
| |
| absl::Status EncodeSerializedSuperBox(absl::Cord payload, |
| riegeli::BackwardWriter* writer) { |
| return WriteRaw(std::move(payload), writer); |
| } |
| |
| absl::Status EncodeContentBox(uint32_t tbox, absl::Cord payload, |
| riegeli::BackwardWriter* writer) { |
| size_t payload_size = payload.size(); |
| ABSL_RETURN_IF_ERROR(WriteRaw(std::move(payload), writer)); |
| return EncodeBoxHeader(payload_size, tbox, writer); |
| } |
| |
| absl::Status EncodeDescriptionBox(credentio::Uuid type_uuid, |
| DescriptionBoxOptions options, |
| riegeli::BackwardWriter* writer) { |
| uint8_t toggles = 0; |
| const riegeli::Position pos_before = writer->pos(); |
| if (options.private_content.has_value()) { |
| toggles |= kDescriptionTogglePrivatePresent; |
| ABSL_RETURN_IF_ERROR(WriteRaw(*std::move(options.private_content), writer)); |
| } |
| if (options.label.has_value()) { |
| if (options.requestable_iff_label) { |
| toggles |= kDescriptionToggleRequestable; |
| } |
| toggles |= kDescriptionToggleLabelPresent; |
| ABSL_RETURN_IF_ERROR(WriteNulTerminated(*std::move(options.label), writer)); |
| } |
| ABSL_RETURN_IF_ERROR(WriteInteger(toggles, writer)); |
| ABSL_RETURN_IF_ERROR(WriteRaw(absl::Cord(type_uuid.ToProtoBytes()), writer)); |
| return EncodeBoxHeader(writer->pos() - pos_before, kDescriptionBoxType, |
| writer); |
| } |
| |
| absl::Status EncodeBoxHeader(riegeli::Position payload_length, uint32_t tbox, |
| riegeli::BackwardWriter* writer) { |
| // Minimum box length is payload + mandatory header fields. |
| constexpr size_t kMandatoryHeaderLength = |
| 2 * sizeof(uint32_t); // LBox and TBox |
| if (payload_length > std::numeric_limits<size_t>::max() - |
| kMandatoryHeaderLength - sizeof(uint64_t)) { |
| return absl::OutOfRangeError("maximum box size exceeded"); |
| } |
| size_t box_length = payload_length + kMandatoryHeaderLength; |
| uint32_t lbox; |
| if (box_length > std::numeric_limits<uint32_t>::max()) { |
| uint64_t xlbox = box_length + sizeof(uint64_t); |
| ABSL_RETURN_IF_ERROR(WriteInteger(xlbox, writer)); |
| lbox = 1; |
| } else { |
| lbox = box_length; |
| } |
| ABSL_RETURN_IF_ERROR(WriteInteger(tbox, writer)); |
| return WriteInteger(lbox, writer); |
| } |
| |
| } // namespace jumbf |