mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
4a2cd259e3
Add the GzipTarFileWriter and GzipTarReader classes that allow reading a slightly custom `.tar.gz`.
99 lines
3.0 KiB
C++
99 lines
3.0 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "revng/Support/Assert.h"
|
|
#include "revng/Support/Generator.h"
|
|
|
|
extern "C" {
|
|
struct archive;
|
|
}
|
|
|
|
namespace revng {
|
|
|
|
struct OffsetDescriptor {
|
|
size_t Start;
|
|
size_t DataStart;
|
|
size_t PaddingStart;
|
|
size_t End;
|
|
|
|
size_t headerSize() { return DataStart - Start; }
|
|
size_t dataSize() { return PaddingStart - DataStart; }
|
|
size_t paddingSize() { return End - PaddingStart; }
|
|
};
|
|
|
|
/// Class that allows writing a '.tar.gz' file conforming to the PAX archive
|
|
/// format. The archive is created with these additional properties:
|
|
/// * The header of each file is a stand-alone gzip stream
|
|
/// * Each file is packaged in a stand-alone gzip stream
|
|
/// * The trailing padding is also a stand-alone gzip stream
|
|
///
|
|
/// The most important property of this arrangement is that it allows each
|
|
/// individual file to be read from the archive without decompressing the entire
|
|
/// archive.
|
|
///
|
|
/// Given the offset and size of a single file, the following command line
|
|
/// invocation will retrieve it:
|
|
/// \code{.sh}
|
|
/// dd if=archive bs=1 skip=$offset count=$size | gunzip
|
|
/// \endcode
|
|
/// Because of this, the ::append method, which is used to add a file to the
|
|
/// archive, returns an OffsetDescriptor object describing the position in the
|
|
/// compressed file of where each gzip stream starts and ends. This allows users
|
|
/// of this class to make an index file that tracks the location of each file.
|
|
///
|
|
/// Additionally, since the gzip standard allows concatenating streams, the file
|
|
/// produced is still a valid '.tar.gz' file that can be opened by any program
|
|
/// that supports "ordinary" '.tar.gz' files.
|
|
class GzipTarWriter {
|
|
private:
|
|
llvm::raw_ostream *OS = nullptr;
|
|
llvm::StringSet<> Filenames;
|
|
|
|
public:
|
|
GzipTarWriter(llvm::raw_ostream &OS) : OS(&OS){};
|
|
~GzipTarWriter() { revng_assert(OS == nullptr); }
|
|
|
|
GzipTarWriter(const GzipTarWriter &Other) = delete;
|
|
GzipTarWriter &operator=(const GzipTarWriter &Other) = delete;
|
|
|
|
GzipTarWriter(GzipTarWriter &&Other) = default;
|
|
GzipTarWriter &operator=(GzipTarWriter &&Other) = default;
|
|
|
|
OffsetDescriptor append(llvm::StringRef Name, llvm::ArrayRef<char> Data);
|
|
void close();
|
|
};
|
|
|
|
struct ArchiveEntry {
|
|
std::string Filename;
|
|
llvm::SmallVector<char> Data;
|
|
};
|
|
|
|
class GzipTarReader {
|
|
private:
|
|
archive *Archive = nullptr;
|
|
|
|
public:
|
|
GzipTarReader(llvm::ArrayRef<char> Ref);
|
|
GzipTarReader(const llvm::MemoryBuffer &Buffer) :
|
|
GzipTarReader({ Buffer.getBufferStart(), Buffer.getBufferSize() }){};
|
|
~GzipTarReader();
|
|
|
|
GzipTarReader(const GzipTarReader &Other) = delete;
|
|
GzipTarReader &operator=(const GzipTarReader &Other) = delete;
|
|
|
|
GzipTarReader(GzipTarReader &&Other) = default;
|
|
GzipTarReader &operator=(GzipTarReader &&Other) = default;
|
|
|
|
cppcoro::generator<ArchiveEntry> entries();
|
|
};
|
|
|
|
} // namespace revng
|