blob: 36d4056f0200402a3fb4b31f4e71c466592a76d6 [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.
//
#ifndef THIRD_PARTY_CREDENTIO_BINDINGS_BINDING_HASHER_H_
#define THIRD_PARTY_CREDENTIO_BINDINGS_BINDING_HASHER_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/base/nullability.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "bindings/input_hasher.h"
#include "riegeli/bytes/reader.h"
namespace credentio {
// A tracker to record the errors during the process of digesting a hard binding
// (e.g., a BMFF file).
class BindingHasherTracker {
public:
virtual ~BindingHasherTracker() = default;
virtual void RecordMismatch() = 0;
virtual void RecordMalformed() = 0;
virtual void RecordAlgorithmUnsupported() = 0;
virtual void RecordGeneralError(absl::Status status) = 0;
};
// A BindingHasherTracker implementation that produces an absl::Status.
class StatusBindingHasherTracker : public BindingHasherTracker {
public:
void RecordMismatch() override {
status_.Update(absl::InvalidArgumentError("mismatch"));
}
void RecordMalformed() override {
status_.Update(absl::InvalidArgumentError("malformed"));
}
void RecordAlgorithmUnsupported() override {
status_.Update(absl::InvalidArgumentError("algorithm unsupported"));
}
void RecordGeneralError(absl::Status status) override {
status_.Update(status);
}
absl::Status status() const { return status_; }
private:
absl::Status status_ = absl::OkStatus();
};
// A hasher to digest a file according to the C2PA Spec. In particular, this
// hasher supports excluding, including or inserting data.
class BindingHasher {
public:
struct Chunk {
// Defines the type of operation; whether to exclude, insert or include the
// chunk into the hasher.
enum class Op { kExclusion, kInsertion, kInclusion };
Op op; // Type of operation, like exclusion or insertion.
uint64_t offset; // The absolute offset of the content to be digested.
// The length of the chunk. If zero and the Op is kExclusion or kInclusion,
// the chunk includes the rest of the content. When the Op is kInsertion,
// the length is ignored, and the whole additional_data will be inserted.
int64_t length;
// Additional data for insertion. Only suitable for small data, like the
// offset of a root box, which is as an 8-byte integer in the big-endian
// format when digesting a BMFF file by the C2PA Spec (`c2pa.hash.bmff.v2`).
std::string additional_data;
};
// The chunks must be ordered by offset and non-overlapping.
BindingHasher(std::unique_ptr<InputHasher> hasher, std::vector<Chunk> chunks)
: hasher_(std::move(hasher)), chunks_(std::move(chunks)) {}
// Digest the input file. The start_offset is the offset of the first byte
// of the data to digest. The end_offset is the offset with respect to the
// start of the entire file of the last byte of the data to digest, -1 means
// the end of the file.
std::optional<std::string> Digest(riegeli::Reader& input,
BindingHasherTracker& tracker,
uint64_t start_offset = 0,
int64_t end_offset = -1);
static absl_nullable std::unique_ptr<BindingHasher> Create(
absl::string_view alg, std::vector<Chunk> chunks,
BindingHasherTracker& tracker);
private:
std::unique_ptr<InputHasher> hasher_;
std::vector<Chunk> chunks_;
};
} // namespace credentio
#endif // THIRD_PARTY_CREDENTIO_BINDINGS_BINDING_HASHER_H_