blob: 1b628bb6060133e3addd94f8b32274aa9eb6b68b [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/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