blob: 95d673574a185e855e8872f7fe05337ee89f9767 [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 "formats/bmff/xpath.h"
#include <string>
#include <vector>
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
namespace credentio {
namespace {
// Returns true if the given path matches the pattern. Like,
// "/a[1]" matches "/a[1]";
// "/a[1]" also matches "/a";
// but "/a[1]" doesn't match "/a[2]".
// Similarly, "/a[1]/b[2]/c[3]" matches "/a/b/c", "/a[1]/b/c", "/a/b[2]/c",
// "/a/b/c[3]", etc;
// but "/a[2]/b[2]/c[3]" doesn't match "/a[1]/b/c".
// Note that while patterns like "/a/b/c" are expected, we don't expect to see
// paths like "/a/b/c" because positional indexes should always be applied in
// the path.
bool MatchXPath(absl::string_view path, absl::string_view pattern) {
if (path == pattern) {
return true;
}
std::vector<absl::string_view> terms_a = absl::StrSplit(path, '/');
std::vector<absl::string_view> terms_b = absl::StrSplit(pattern, '/');
if (terms_a.size() != terms_b.size()) {
return false;
}
for (int i = 0; i < terms_a.size(); ++i) {
if (terms_a[i] == terms_b[i]) {
continue;
}
if (absl::StrContains(terms_b[i], "[")) {
// Term b is a positioned element; requires exact match.
return false;
}
absl::string_view remainder = terms_a[i];
if (absl::ConsumePrefix(&remainder, terms_b[i]) &&
absl::StartsWith(remainder, "[")) {
continue;
}
return false;
}
return true;
};
} // namespace
bool XPathMatcher::Matches(absl::string_view path) const {
return MatchXPath(path, pattern_);
}
std::string XPath::ToString() const {
std::string result;
for (const XPath* cursor = this; cursor != nullptr;
cursor = cursor->parent_) {
std::string element_name =
absl::StrCat("/", cursor->name_,
cursor->position_.has_value()
? absl::StrCat("[", *cursor->position_, "]")
: "");
result = absl::StrCat(element_name, result);
}
return result;
}
} // namespace credentio