| // 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/serialization_utils.h" | |
| #include <climits> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <utility> | |
| #include "absl/status/status.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/cord.h" | |
| #include "absl/strings/match.h" | |
| #include "absl/strings/str_cat.h" | |
| #include "absl/strings/string_view.h" | |
| #include "riegeli/base/byte_fill.h" | |
| #include "riegeli/bytes/backward_writer.h" | |
| #include "riegeli/endian/endian_writing.h" | |
| #define WRITER_CALL_OR_RETURN(writer, call) \ | |
| do { \ | |
| if (!writer->call) { \ | |
| return writer->status(); \ | |
| } \ | |
| } while (false) | |
| namespace jumbf_internal { | |
| // This library stores non-text data in strings and string_views, and reads | |
| // values from byte offsets within them. No effort has been made to take into | |
| // account alternate char widths. | |
| static_assert(CHAR_BIT == 8); | |
| absl::StatusOr<absl::string_view> ConsumeNullTerminated(absl::string_view* sv) { | |
| size_t len = sv->find('\0'); | |
| if (len == absl::string_view::npos) { | |
| return absl::OutOfRangeError( | |
| "ran out of input bytes before reading null terminator"); | |
| } | |
| // `len` does not include null terminator, which would have been contained | |
| // within the bounds of `sv`. | |
| absl::string_view output = sv->substr(0, len); | |
| sv->remove_prefix(len + 1); | |
| return output; | |
| } | |
| // Consumes the first `n` bytes of `sv`. | |
| absl::StatusOr<absl::string_view> ConsumeBytes(absl::string_view* sv, | |
| size_t n) { | |
| if (sv->length() < n) { | |
| return absl::OutOfRangeError(absl::StrCat("ran out of input bytes; ", n, | |
| " bytes requested, ", | |
| sv->length(), " remaining")); | |
| } | |
| absl::string_view output = sv->substr(0, n); | |
| sv->remove_prefix(n); | |
| return output; | |
| } | |
| absl::Status WriteRaw(absl::Cord content, riegeli::BackwardWriter* writer) { | |
| WRITER_CALL_OR_RETURN(writer, Write(std::move(content))); | |
| return absl::OkStatus(); | |
| } | |
| absl::Status WriteNulTerminated(absl::Cord content, | |
| riegeli::BackwardWriter* writer) { | |
| for (absl::string_view chunk : content.Chunks()) { | |
| if (absl::StrContains(chunk, '\0')) { | |
| return absl::InvalidArgumentError( | |
| "cannot create NUL-terminated string from content: content contains " | |
| "NUL"); | |
| } | |
| } | |
| WRITER_CALL_OR_RETURN(writer, WriteByte('\0')); | |
| WRITER_CALL_OR_RETURN(writer, Write(std::move(content))); | |
| return absl::OkStatus(); | |
| } | |
| template <> | |
| absl::Status WriteInteger(uint8_t n, riegeli::BackwardWriter* writer) { | |
| WRITER_CALL_OR_RETURN(writer, WriteByte(n)); | |
| return absl::OkStatus(); | |
| } | |
| template <> | |
| absl::Status WriteInteger(uint32_t n, riegeli::BackwardWriter* writer) { | |
| char buf[4]; | |
| riegeli::WriteBigEndian<uint32_t>(n, buf); | |
| WRITER_CALL_OR_RETURN(writer, Write(absl::string_view(buf, 4))); | |
| return absl::OkStatus(); | |
| } | |
| template <> | |
| absl::Status WriteInteger(uint64_t n, riegeli::BackwardWriter* writer) { | |
| char buf[8]; | |
| riegeli::WriteBigEndian<uint64_t>(n, buf); | |
| WRITER_CALL_OR_RETURN(writer, Write(absl::string_view(buf, 8))); | |
| return absl::OkStatus(); | |
| } | |
| absl::Status WritePadding(uint64_t length, riegeli::BackwardWriter* writer) { | |
| WRITER_CALL_OR_RETURN(writer, Write(riegeli::ByteFill(length))); | |
| return absl::OkStatus(); | |
| } | |
| } // namespace jumbf_internal |