diff --git a/soup/Reader.hpp b/soup/Reader.hpp index 48164c69..331e7c88 100644 --- a/soup/Reader.hpp +++ b/soup/Reader.hpp @@ -1,5 +1,7 @@ #pragma once +#include // memset + #include "ioBase.hpp" #include "fwd.hpp" @@ -193,6 +195,13 @@ NAMESPACE_SOUP return raw(v.data(), len); } + // String with known length. + bool str(size_t len, char* v) SOUP_EXCAL + { + memset(v, 0, len); + return raw(v, len); + } + // std::vector with u8 size prefix. bool vec_u8_u8(std::vector& v) SOUP_EXCAL { diff --git a/soup/Soup.vcxproj b/soup/Soup.vcxproj index f6db8a84..f79221de 100644 --- a/soup/Soup.vcxproj +++ b/soup/Soup.vcxproj @@ -848,6 +848,8 @@ + + @@ -1367,6 +1369,7 @@ + diff --git a/soup/Soup.vcxproj.filters b/soup/Soup.vcxproj.filters index 71a8a700..bfe23b32 100644 --- a/soup/Soup.vcxproj.filters +++ b/soup/Soup.vcxproj.filters @@ -1668,6 +1668,12 @@ util + + io\tar + + + io\tar + @@ -2489,6 +2495,9 @@ util\hooks + + io\tar + @@ -2749,6 +2758,9 @@ {a7f4aeee-77a2-4381-a5cb-7d9492511b79} + + {362041cb-1458-4b94-a12e-e5369f3ce84e} + diff --git a/soup/TarIndexedFile.hpp b/soup/TarIndexedFile.hpp new file mode 100644 index 00000000..0a800ea1 --- /dev/null +++ b/soup/TarIndexedFile.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "base.hpp" + +NAMESPACE_SOUP +{ + struct TarIndexedFile + { + char name[101]; + size_t offset; + size_t size; + }; +} diff --git a/soup/TarReader.cpp b/soup/TarReader.cpp new file mode 100644 index 00000000..2cb21b01 --- /dev/null +++ b/soup/TarReader.cpp @@ -0,0 +1,48 @@ +#include "TarReader.hpp" + +#include "string.hpp" + +NAMESPACE_SOUP +{ + std::vector TarReader::getFileList() const SOUP_EXCAL + { + r.seekEnd(); + const size_t tarsize = r.getPosition(); + SOUP_IF_UNLIKELY ((tarsize % 512) != 0) + { + return {}; // Not a valid tarball + } + + std::vector res{}; + for (size_t i = 0; i != tarsize; ) + { + r.seek(i + 124); + char size_octal[13]; + memset(size_octal, 0, sizeof(size_octal)); + r.raw(size_octal, 12); + size_t size; + SOUP_IF_UNLIKELY (!string::toIntEx(size_octal, string::TI_FULL).consume(size)) + { + break; // Tarball might end on a null block + } + + r.seek(i + 156); + char type; + r.c(type); + if (type == '\0' || type == '0') // Regular file? + { + auto& file = res.emplace_back(); + + memset(file.name, 0, sizeof(file.name)); + r.seek(i); + r.raw(file.name, 100); + + file.offset = i + 512; + file.size = size; + } + + i += ((1 + ((size + 511) / 512)) * 512); + } + return res; + } +} diff --git a/soup/TarReader.hpp b/soup/TarReader.hpp new file mode 100644 index 00000000..c9ee6a07 --- /dev/null +++ b/soup/TarReader.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "Reader.hpp" +#include "TarIndexedFile.hpp" + +NAMESPACE_SOUP +{ + struct TarReader + { + Reader& r; + + TarReader(Reader& r) noexcept + : r(r) + { + } + + [[nodiscard]] std::vector getFileList() const SOUP_EXCAL; + + [[nodiscard]] std::string getFileContents(const TarIndexedFile& file) const SOUP_EXCAL + { + r.seek(file.offset); + std::string res(file.size, '\0'); + r.raw(res.data(), file.size); + return res; + } + }; +}