| // 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/pdf/manifest_store_merger.h" | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include "absl/status/status.h" | |
| #include "absl/status/status_macros.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/cord.h" | |
| #include "absl/strings/string_view.h" | |
| #include "absl/types/span.h" | |
| #include "constants/labels.h" | |
| #include "jumbf/box.h" | |
| #include "jumbf/box_builder.h" | |
| #include "jumbf/encode_params.h" | |
| #include "jumbf/parse.h" | |
| namespace credentio { | |
| using ::jumbf::DescriptionBoxOptions; | |
| using ::jumbf::SuperBox; | |
| using ::jumbf::SuperBoxBuilder; | |
| absl::StatusOr<std::string> MergeManifestStores( | |
| absl::Span<const absl::string_view> stores) { | |
| if (stores.empty()) { | |
| return absl::InvalidArgumentError("No manifest stores provided to merge."); | |
| } | |
| if (stores.size() == 1) { | |
| return std::string(stores.front()); | |
| } | |
| SuperBoxBuilder builder(credentio::kManifestStoreUuid, | |
| DescriptionBoxOptions{ | |
| .requestable_iff_label = true, | |
| .label = absl::Cord(kManifestStoreLabel), | |
| }); | |
| // SuperBoxBuilder uses a CordBackwardWriter (LIFO insertion order). | |
| // To ensure the newest PDF increment's manifest ends up at the BACK of the | |
| // content list, we iterate through stores in REVERSE chronological order | |
| // (stores.rbegin() to stores.rend()). | |
| for (auto store_it = stores.rbegin(); store_it != stores.rend(); ++store_it) { | |
| absl::string_view store_view = *store_it; | |
| ABSL_ASSIGN_OR_RETURN( | |
| SuperBox ms_superbox, | |
| jumbf::ConsumeSuperBox(&store_view, /*recursion_limit=*/9)); | |
| // Iterate contents in REVERSE order so LIFO AddChild restores the exact | |
| // original order of children inside each store. | |
| for (auto box_it = ms_superbox.contents.rbegin(); | |
| box_it != ms_superbox.contents.rend(); ++box_it) { | |
| ABSL_RETURN_IF_ERROR(builder.AddChild(absl::Cord(box_it->raw_bytes))); | |
| } | |
| } | |
| ABSL_ASSIGN_OR_RETURN(auto built_box, std::move(builder).Finalize()); | |
| return std::string(std::move(built_box).AsCord()); | |
| } | |
| } // namespace credentio |