blob: b7919b0e7c983f693610240a2bec703cd1fcf0f3 [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/internal/consume_box.h"
#include <cstddef>
#include <cstdint>
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "jumbf/internal/intermediate.h"
#include "jumbf/internal/serialization_utils.h"
namespace jumbf_internal {
absl::StatusOr<IntermediateBox> ConsumeBox(absl::string_view* input,
bool allow_implicit_length) {
absl::string_view temp_input = *input;
auto lbox = ConsumeInteger<uint32_t>(&temp_input);
if (!lbox.ok()) {
return absl::Status(
lbox.status().code(),
absl::StrCat("cannot read LBox value: ", lbox.status().message()));
}
auto tbox = ConsumeInteger<uint32_t>(&temp_input);
if (!tbox.ok()) {
return absl::Status(
tbox.status().code(),
absl::StrCat("cannot read TBox value: ", tbox.status().message()));
}
uint64_t box_length;
if (*lbox == 0) {
if (allow_implicit_length) {
box_length = input->length();
} else {
return absl::InvalidArgumentError(
R"(LBox is 0, indicating box extends to end of input, but context does not allow for implicit box lengths; implicit boxes are only allowed if they are the last box in the file, and if they are contained within a super box, that super box must also have an implicit length)");
}
} else if (*lbox == 1) {
auto xlbox = ConsumeInteger<uint64_t>(&temp_input);
if (!xlbox.ok()) {
return absl::Status(
xlbox.status().code(),
absl::StrCat("cannot read XLBox value: ", xlbox.status().message()));
}
if (*xlbox < 16) {
return absl::InvalidArgumentError(absl::StrCat(
"XLBox is ", *xlbox,
", which is less than the number of bytes already consumed by "
"this box's header"));
}
box_length = *xlbox;
} else if (*lbox <= 7) {
return absl::InvalidArgumentError(absl::StrCat(
"LBox is ", *lbox, "; LBox values 2-7 are reserved by the standard"));
} else {
box_length = *lbox;
}
if (box_length > input->length()) {
return absl::InvalidArgumentError(absl::StrCat(
"not enough input bytes for declared box size; have ", input->length(),
" input bytes, box declares its size as ", box_length, " bytes"));
}
size_t header_bytes = temp_input.data() - input->data();
absl::string_view serialized = input->substr(0, box_length);
input->remove_prefix(box_length);
return IntermediateBox{
.payload = temp_input.substr(0, box_length - header_bytes),
.serialized = serialized,
.type = *tbox,
.implicit_length = *lbox == 0,
};
}
} // namespace jumbf_internal