Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
ArchiveWriter.cpp
Go to the documentation of this file.
2
6
7namespace storm::io {
8
9#ifdef STORM_HAVE_LIBARCHIVE
10ArchiveWriter::ArchiveWriter(std::filesystem::path const& filename, CompressionMode const compression) : _archive(archive_write_new(), ArchiveDeleter{}) {
11 STORM_LOG_THROW(_archive, storm::exceptions::FileIoException, "Failed to create archive reader.");
12
13 // Set format to gzipped TAR with restricted pax extensions
14 switch (compression) {
15 case CompressionMode::None:
16 break;
17 case CompressionMode::Gzip:
18 archive_write_add_filter_gzip(_archive.get());
19 break;
20 case CompressionMode::Xz:
21 case CompressionMode::Default: // Following suggestions from UMB, we use xz as default compression
22 archive_write_add_filter_xz(_archive.get());
23 break;
24 default:
25 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported compression mode.");
26 }
27 checkResult(archive_write_set_format_pax_restricted(_archive.get()));
28
29 // Open file for writing
30 checkResult(archive_write_open_filename(_archive.get(), filename.c_str()));
31}
32#else
33ArchiveWriter::ArchiveWriter(std::filesystem::path const&, CompressionMode const) {
34 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException, "Writing archives is not supported. Storm is compiled without LibArchive.");
35}
36#endif
37
38void ArchiveWriter::addDirectory(std::filesystem::path const& archivePath) {
39#ifdef STORM_HAVE_LIBARCHIVE
40
41 archive_entry* entry = archive_entry_new();
42 STORM_LOG_THROW(entry, storm::exceptions::FileIoException, "Failed to create archive entry.");
43
44 // Fill in metadata: path, file type, permissions, etc.
45 archive_entry_set_pathname(entry, archivePath.c_str());
46 archive_entry_set_filetype(entry, AE_IFDIR);
47 archive_entry_set_perm(entry, 0777);
48
49 // Write the header (metadata) to the archive
50 checkResult(archive_write_header(_archive.get(), entry), entry);
51
52 // Free the entry metadata after we finish writing
53 archive_entry_free(entry);
54#else
55 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException, "Writing archives is not supported. Storm is compiled without LibArchive.");
56#endif
57}
58
59void ArchiveWriter::addFile(std::filesystem::path const& archivePath, char const* data, std::size_t const size) {
60 std::size_t startOfChunk = 0;
61 auto getNextChunk = [&]() {
62 auto const chunkSize = std::min<std::size_t>(size - startOfChunk, BufferSize);
63 auto const chunk = std::span<char const>(data + startOfChunk, chunkSize);
64 startOfChunk += chunkSize;
65 return chunk;
66 };
67 addFileFromChunks(archivePath, getNextChunk, size);
68}
69
70void ArchiveWriter::addBinaryFile(std::filesystem::path const& archivePath, storm::storage::BitVector const& data) {
71 using BucketType = decltype(std::declval<storm::storage::BitVector&>().getBucket({}));
72 static_assert(BufferSize % sizeof(BucketType) == 0, "Buffer size must be a multiple of sizeof(BucketType).");
73 std::array<BucketType, BufferSize / sizeof(BucketType)> buffer;
74
75 // need to reverse bits and potentially swap bytes
76 uint64_t startOfChunk = 0;
77 auto getNextChunk = [&data, &buffer, &startOfChunk]() -> std::span<const char> {
78 auto const endOfChunk = std::min<uint64_t>(startOfChunk + buffer.size(), data.bucketCount());
79 auto bufferIt = buffer.begin();
80 for (uint64_t i = startOfChunk; i < endOfChunk; ++i) {
81 // reverse bits so that the first bit of the first byte is data.get(0).
82 bool constexpr NativeLittleEndian = std::endian::native == std::endian::little;
83 *bufferIt = storm::utility::reverseBits<BucketType, NativeLittleEndian>(data.getBucket(i));
84 ++bufferIt;
85 }
86 std::span<const char> chunk(reinterpret_cast<const char*>(buffer.data()), (endOfChunk - startOfChunk) * sizeof(BucketType));
87 startOfChunk = endOfChunk;
88 return chunk;
89 };
90 uint64_t const numBytes = data.bucketCount() * sizeof(BucketType);
91 addFileFromChunks(archivePath, getNextChunk, numBytes);
92}
93
94void ArchiveWriter::addTextFile(std::filesystem::path const& archivePath, std::string const& data) {
95 addFile(archivePath, data.c_str(), data.size());
96}
97
98#ifdef STORM_HAVE_LIBARCHIVE
99void ArchiveWriter::checkResult(auto resultCode, archive_entry* entry) const {
100 STORM_LOG_THROW(_archive, storm::exceptions::FileIoException, "Unexpected result: Archive not loaded.");
101
102 STORM_LOG_WARN_COND(std::cmp_greater_equal(resultCode, ARCHIVE_OK), "Unexpected result from archive: " << archive_error_string(_archive.get()) << ".");
103 if (std::cmp_less(resultCode, ARCHIVE_WARN)) {
104 if (entry) {
105 archive_entry_free(entry);
106 }
107 STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Unexpected result from archive: " << archive_error_string(_archive.get()) << ".");
108 }
109}
110
111void ArchiveWriter::ArchiveDeleter::operator()(archive* arch) const noexcept {
112 if (arch) {
113 archive_free(arch);
114 }
115}
116#endif
117
118} // namespace storm::io
ArchiveWriter(std::filesystem::path const &filename, CompressionMode const compression)
Create a new archive and open it as a file on disk.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
uint64_t getBucket(uint64_t bucketIndex) const
Gets the bits in the given bucket.
size_t bucketCount() const
Retrieves the number of buckets of the underlying storage.
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30