blob: 97e155532a93d1af57e3192056fc06214e1f8b72 [file] [edit]
// 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/utils.h"
#include <sys/types.h>
#include <cstdint>
#include <utility>
#include <variant>
#include "absl/functional/overload.h"
#include "absl/status/status.h"
#include "absl/status/status_macros.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "jumbf/box.h"
#include "jumbf/constants.h"
#include "jumbf/internal/serialization_utils.h"
#include "uuid/uuid.h"
namespace jumbf {
namespace {
// Consumes the header of a JUMBF Box and returns the TBox.
//
// The header is a 4 byte unsigned integer (LBox) followed by a 4 byte unsigned
// integer (TBox). If the first integer is 1, it's followed by a 8 byte unsigned
// integer (XLBox).
absl::StatusOr<uint32_t> ConsumeHeader(absl::string_view* payload) {
ABSL_ASSIGN_OR_RETURN(auto lbox,
jumbf_internal::ConsumeInteger<uint32_t>(payload));
ABSL_ASSIGN_OR_RETURN(auto tbox,
jumbf_internal::ConsumeInteger<uint32_t>(payload));
if (lbox == 1) {
ABSL_RETURN_IF_ERROR(
jumbf_internal::ConsumeBytes(payload, sizeof(uint64_t)).status());
}
return tbox;
}
} // namespace
absl::StatusOr<absl::string_view> StripBoxHeaders(absl::string_view raw_bytes) {
ABSL_ASSIGN_OR_RETURN(auto lbox,
jumbf_internal::ConsumeInteger<uint32_t>(&raw_bytes));
ABSL_RETURN_IF_ERROR(
jumbf_internal::ConsumeBytes(&raw_bytes, sizeof(uint32_t)).status());
if (lbox == 1) {
ABSL_RETURN_IF_ERROR(
jumbf_internal::ConsumeBytes(&raw_bytes, sizeof(uint64_t)).status());
}
return raw_bytes;
}
absl::StatusOr<bool> HasDescriptionBoxMatching(absl::string_view raw_bytes,
const credentio::Uuid& uuid,
uint8_t toggles_mask,
absl::string_view label) {
// Super Box Header
ABSL_ASSIGN_OR_RETURN(auto super_tbox, ConsumeHeader(&raw_bytes));
if (super_tbox != kSuperBoxType) {
return false;
}
// Description Box Header
ABSL_ASSIGN_OR_RETURN(auto description_tbox, ConsumeHeader(&raw_bytes));
if (description_tbox != kDescriptionBoxType) {
return false;
}
// Description Box UUID
if (raw_bytes.size() < 16) {
return absl::OutOfRangeError("Description Box UUID is missing.");
}
ABSL_ASSIGN_OR_RETURN(auto description_uuid, credentio::Uuid::FromProtoBytes(
raw_bytes.substr(0, 16)));
raw_bytes.remove_prefix(16);
if (std::move(description_uuid) != uuid) {
return false;
}
// Description Box Toggles
ABSL_ASSIGN_OR_RETURN(auto toggles,
jumbf_internal::ConsumeInteger<uint8_t>(&raw_bytes));
if ((toggles & toggles_mask) != toggles_mask) {
return false;
}
// Expected Label
if (!absl::ConsumePrefix(&raw_bytes, label)) {
return false;
}
// Ensure the next character is the null terminator
ABSL_ASSIGN_OR_RETURN(auto next_byte,
jumbf_internal::ConsumeInteger<uint8_t>(&raw_bytes));
return next_byte == 0x00;
}
int GetContextBoxSize(const ContentBox& box) {
int content_size = 0;
std::visit(
absl::Overload{
[&](const UnknownBox& arg) { content_size = arg.payload.size(); },
[&](const CborBox& arg) { content_size = arg.payload.size(); },
[&](const SerializedSuperbox& arg) {
content_size = arg.serialized.size();
},
[&](const SuperBox& arg) { content_size = arg.raw_bytes.size(); },
[&](const EmbeddedFileDescriptionBox& arg) {
// See section B.6.2
// Always include a byte for toggles
content_size = 1;
// Add media type size + 1 for null terminator
content_size += arg.media_type.size() + 1;
if (arg.file_name.has_value()) {
// Add file name size + 1 for null terminator
content_size += arg.file_name->size() + 1;
}
},
[&](const BinaryDataBox& arg) { content_size = arg.payload.size(); },
[&](const C2paSaltBox& arg) { content_size = arg.salt.size(); },
[&](const JsonBox& arg) { content_size = arg.payload.size(); },
[&](const UuidBox& arg) { content_size = arg.payload.size(); },
},
box.payload);
return content_size;
}
} // namespace jumbf