| // 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 "formats/bmff/box_matcher.h" | |
| #include <cstdint> | |
| #include <string> | |
| #include <vector> | |
| #include "formats/bmff/box_header.h" | |
| #include "formats/bmff/xpath.h" | |
| #include "proto/bmff_based_hash_assertion.pb.h" | |
| namespace credentio { | |
| namespace { | |
| uint32_t NetworkUInt24(std::string value) { | |
| uint32_t result = 0; | |
| for (int i = 0; i < 3; ++i) { | |
| uint8_t byte = (i < value.size()) ? static_cast<uint8_t>(value[i]) : 0; | |
| result = (result << 8) | byte; | |
| } | |
| return result; | |
| } | |
| bool MatchLength(const BmffRange& bmff_range, const BmffBoxHeader& header) { | |
| if (!bmff_range.has_length()) { | |
| return true; | |
| } | |
| return header.box_size == bmff_range.length(); | |
| } | |
| bool MatchVersion(const BmffRange& bmff_range, const BmffBoxHeader& header) { | |
| if (!bmff_range.has_version()) { | |
| return true; | |
| } | |
| return header.version == bmff_range.version(); | |
| } | |
| bool MatchFlags(const BmffRange& bmff_range, const BmffBoxHeader& header) { | |
| if (!bmff_range.has_flags()) { | |
| return true; | |
| } | |
| if (!header.IsFullBox()) { | |
| return false; | |
| } | |
| if (!bmff_range.has_exact() || bmff_range.exact()) { | |
| return header.flags == bmff_range.flags(); | |
| } | |
| auto desired_flags = NetworkUInt24(std::string(bmff_range.flags())); | |
| auto box_flags = NetworkUInt24(header.flags); | |
| return (desired_flags & box_flags) == desired_flags; | |
| } | |
| } // namespace | |
| bool BMFFBoxMatcher::Matches(BmffBoxHeader header) const { | |
| if (!(XPathMatcher(bmff_range_.xpath()).Matches(header.xpath)) || | |
| !MatchLength(bmff_range_, header) || !MatchVersion(bmff_range_, header) || | |
| !MatchFlags(bmff_range_, header)) { | |
| return false; | |
| } | |
| for (const auto& data : bmff_range_.data()) { | |
| uint64_t offset = header.start + data.offset(); | |
| input_.Seek(offset); | |
| if (input_.pos() != offset) { | |
| return false; | |
| } | |
| std::string value; | |
| if (!input_.Read(data.value().size(), value)) { | |
| return false; | |
| } | |
| if (value != data.value()) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| std::vector<BMFFBoxMatcher::Range> BMFFBoxMatcher::MatchedRanges( | |
| BmffBoxHeader header) const { | |
| std::vector<Range> ranges; | |
| if (bmff_range_.subsets_size() == 0) { | |
| ranges.push_back({.offset = header.start, | |
| .length = static_cast<int64_t>(header.box_size)}); | |
| return ranges; | |
| } | |
| for (const auto& subset : bmff_range_.subsets()) { | |
| int64_t offset = header.start + subset.offset(); | |
| int64_t end = header.start + subset.offset() + subset.length(); | |
| if (offset > end) { | |
| // Invalid subset. | |
| continue; | |
| } | |
| if (subset.length() == 0 || end > header.start + header.box_size) { | |
| end = header.start + header.box_size; | |
| } | |
| ranges.push_back( | |
| {.offset = header.start + subset.offset(), .length = end - offset}); | |
| } | |
| return ranges; | |
| } | |
| } // namespace credentio |