General improvements to pack (#171)
* All tests pass, pack and unpack work, makeappx can unpack * Add RelWithDebInfo option for Windows, fix bug with negative seek in x86, PR feedback
This commit is contained in:
Родитель
4b7c4089ba
Коммит
d4508c9b45
|
@ -43,6 +43,12 @@ if /I "%~2" == "--debug" (
|
|||
if /I "%~2" == "-d" (
|
||||
set build="Debug"
|
||||
)
|
||||
if /I "%~2" == "--symbols" (
|
||||
set build="RelWithDebInfo"
|
||||
)
|
||||
if /I "%~2" == "-sym" (
|
||||
set build="RelWithDebInfo"
|
||||
)
|
||||
if /I "%~2" == "--parser-xerces" (
|
||||
set parser="-DXML_PARSER=xerces"
|
||||
)
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace MSIX {
|
|||
std::uint64_t sizeRemaining = m_streamSize;
|
||||
for (auto block = blocks.begin(); ((sizeRemaining != 0) && (block != blocks.end())); block++)
|
||||
{
|
||||
auto rangeStream = ComPtr<IStream>::Make<RangeStream>(offset, std::min(sizeRemaining, BLOCKMAP_BLOCK_SIZE), stream);
|
||||
auto rangeStream = ComPtr<IStream>::Make<RangeStream>(offset, std::min(sizeRemaining, BLOCKMAP_BLOCK_SIZE), stream.Get());
|
||||
auto hashStream = ComPtr<IStream>::Make<HashStream>(rangeStream, block->hash);
|
||||
std::uint64_t blockSize = std::min(sizeRemaining, BLOCKMAP_BLOCK_SIZE);
|
||||
|
||||
|
|
|
@ -22,6 +22,11 @@ namespace MSIX {
|
|||
HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newPosition) noexcept override;
|
||||
HRESULT STDMETHODCALLTYPE Read(void* buffer, ULONG countBytes, ULONG* bytesRead) noexcept override;
|
||||
HRESULT STDMETHODCALLTYPE Write(void const *buffer, ULONG countBytes, ULONG *bytesWritten) noexcept override;
|
||||
|
||||
// IStreamInternal
|
||||
std::uint64_t GetSize() override { return m_stream.As<IStreamInternal>()->GetSize(); }
|
||||
bool IsCompressed() override { return m_stream.As<IStreamInternal>()->IsCompressed(); }
|
||||
std::string GetName() override { return m_stream.As<IStreamInternal>()->GetName(); }
|
||||
|
||||
protected:
|
||||
std::vector<std::uint8_t> Deflate(int disposition);
|
||||
|
|
|
@ -76,7 +76,15 @@ namespace MSIX {
|
|||
#endif
|
||||
RaiseException(const int line, const char* const file, const char* details, C c)
|
||||
{
|
||||
assert(false);
|
||||
#ifdef WIN32
|
||||
#ifndef NDEBUG
|
||||
if (IsDebuggerPresent())
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
std::ostringstream builder;
|
||||
if (details) { builder << details << "\n"; }
|
||||
builder << "Call failed in " << file << " on line " << line;
|
||||
|
|
|
@ -46,81 +46,135 @@ class FieldBase
|
|||
public:
|
||||
FieldBase() = default;
|
||||
|
||||
size_t Size() { return sizeof(T); }
|
||||
std::vector<std::uint8_t> GetBytes() { return std::vector<std::uint8_t>(); }
|
||||
|
||||
constexpr size_t Size() const { return sizeof(T); }
|
||||
|
||||
void GetBytes(std::vector<std::uint8_t>& bytes) const
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
for (size_t i = 0; i < Size(); ++i)
|
||||
{
|
||||
bytes.push_back(static_cast<std::uint8_t>(this->value >> (i * 8)));
|
||||
}
|
||||
}
|
||||
|
||||
FieldBase& operator=(const T& v)
|
||||
{
|
||||
value = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
T& get()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
T* operator &()
|
||||
{
|
||||
return &value;
|
||||
}
|
||||
|
||||
protected:
|
||||
T value;
|
||||
};
|
||||
|
||||
// Simple 2, 4, and 8 byte fields
|
||||
class Field2Bytes final : public FieldBase<std::uint16_t>
|
||||
{
|
||||
public:
|
||||
std::vector<std::uint8_t> GetBytes()
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
std::vector<std::uint8_t> result;
|
||||
result.push_back(static_cast<std::uint8_t>(this->value));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 8));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class Field4Bytes final : public FieldBase<std::uint32_t>
|
||||
{
|
||||
public:
|
||||
std::vector<std::uint8_t> GetBytes()
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
std::vector<std::uint8_t> result;
|
||||
result.push_back(static_cast<std::uint8_t>(this->value));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 8));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 16));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 24));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class Field8Bytes final : public FieldBase<std::uint64_t>
|
||||
{
|
||||
public:
|
||||
std::vector<std::uint8_t> GetBytes()
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
std::vector<std::uint8_t> result;
|
||||
result.push_back(static_cast<std::uint8_t>(this->value));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 8));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 16));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 24));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 32));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 40));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 48));
|
||||
result.push_back(static_cast<std::uint8_t>(this->value >> 56));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
using Field2Bytes = FieldBase<std::uint16_t>;
|
||||
using Field4Bytes = FieldBase<std::uint32_t>;
|
||||
using Field8Bytes = FieldBase<std::uint64_t>;
|
||||
|
||||
// variable length field.
|
||||
class FieldNBytes : public FieldBase<std::vector<std::uint8_t>>
|
||||
{
|
||||
public:
|
||||
size_t Size() { return this->value.size(); }
|
||||
std::vector<std::uint8_t> GetBytes()
|
||||
size_t Size() const { return this->value.size(); }
|
||||
|
||||
void GetBytes(std::vector<std::uint8_t>& result) const
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
return this->value;
|
||||
result.insert(result.end(), value.begin(), value.end());
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Base type for individual serializable/deserializable optional fields //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T>
|
||||
class OptionalFieldBase
|
||||
{
|
||||
public:
|
||||
OptionalFieldBase() = default;
|
||||
|
||||
constexpr size_t Size() { return (hasValue ? value.Size() : 0); }
|
||||
|
||||
void GetBytes(std::vector<std::uint8_t>& bytes)
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
if (hasValue)
|
||||
{
|
||||
value.GetBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
OptionalFieldBase& operator=(const T& v)
|
||||
{
|
||||
hasValue = true;
|
||||
value = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return hasValue;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
ThrowErrorIfNot(Error::InvalidState, hasValue, "Cannot retrieve value if none is set");
|
||||
return value;
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
{
|
||||
ThrowErrorIfNot(Error::InvalidState, hasValue, "Cannot retrieve value if none is set");
|
||||
return value.get();
|
||||
}
|
||||
|
||||
T* operator &()
|
||||
{
|
||||
hasValue = true;
|
||||
return &value;
|
||||
}
|
||||
|
||||
protected:
|
||||
FieldBase<T> value;
|
||||
bool hasValue = false;
|
||||
};
|
||||
|
||||
// Simple 2, 4, and 8 byte fields
|
||||
using OptionalField2Bytes = OptionalFieldBase<std::uint16_t>;
|
||||
using OptionalField4Bytes = OptionalFieldBase<std::uint32_t>;
|
||||
using OptionalField8Bytes = OptionalFieldBase<std::uint64_t>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Heterogeneous collection of types that are operated on as a compile-time vector //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename... Types>
|
||||
class TypeList
|
||||
{
|
||||
static constexpr std::size_t last_index { std::tuple_size<std::tuple<Types...>>::value };
|
||||
static constexpr std::size_t last_index { sizeof...(Types) };
|
||||
public:
|
||||
std::tuple<Types...> fields;
|
||||
std::tuple<Types...> fields;
|
||||
|
||||
template<std::size_t index = 0, typename FuncT, class... Args>
|
||||
inline typename std::enable_if<index == last_index, void>::type for_each(FuncT, Args&&... args) { }
|
||||
|
||||
|
@ -133,6 +187,9 @@ public:
|
|||
|
||||
template <size_t index>
|
||||
auto& Field() noexcept { return std::get<index>(fields); }
|
||||
|
||||
template <size_t index>
|
||||
const auto& Field() const noexcept { return std::get<index>(fields); }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -146,7 +203,8 @@ public:
|
|||
{
|
||||
size_t result = 0;
|
||||
this->for_each([](auto& field, std::size_t index, size_t& result)
|
||||
{ result += field.Size();
|
||||
{
|
||||
result += field.Size();
|
||||
}, result);
|
||||
return result;
|
||||
}
|
||||
|
@ -157,8 +215,7 @@ public:
|
|||
std::vector<std::uint8_t> bytes;
|
||||
this->for_each([](auto& field, std::size_t index, std::vector<std::uint8_t>& bytes)
|
||||
{
|
||||
auto fieldBytes = field.GetBytes();
|
||||
bytes.insert(bytes.end(), fieldBytes.begin(), fieldBytes.end());
|
||||
field.GetBytes(bytes);
|
||||
}, bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
#include "Exceptions.hpp"
|
||||
#include "StreamBase.hpp"
|
||||
#include "ComHelper.hpp"
|
||||
#include "VectorStream.hpp"
|
||||
#include "MsixFeatureSelector.hpp"
|
||||
#include "DeflateStream.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
@ -20,41 +18,56 @@ namespace MSIX {
|
|||
class RangeStream : public StreamBase
|
||||
{
|
||||
public:
|
||||
RangeStream(std::uint64_t offset, std::uint64_t size, const ComPtr<IStream>& stream) :
|
||||
RangeStream(std::uint64_t offset, std::uint64_t size, IStream* stream) :
|
||||
m_offset(offset),
|
||||
m_size(size),
|
||||
m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
RangeStream(bool isCompressed) : m_offset(0), m_size(0)
|
||||
// For writing/pack
|
||||
// This simply keeps track of the amount of data written to the stream, as well as
|
||||
// limiting any Read/Seek to the data written, rather than the entire underlying stream.
|
||||
RangeStream(IStream* stream) : m_stream(stream), m_size(0)
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
m_stream = ComPtr<IStream>::Make<VectorStream>(&m_buffer);
|
||||
if (isCompressed)
|
||||
{
|
||||
m_stream = ComPtr<IStream>::Make<DeflateStream>(m_stream);
|
||||
}
|
||||
ULARGE_INTEGER pos = { 0 };
|
||||
ThrowHrIfFailed(m_stream->Seek({ 0 }, Reference::CURRENT, &pos));
|
||||
m_offset = pos.QuadPart;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newPosition) noexcept override try
|
||||
{
|
||||
// Determine new range relative position
|
||||
LARGE_INTEGER newPos = { 0 };
|
||||
switch (origin)
|
||||
{
|
||||
case Reference::CURRENT:
|
||||
newPos.QuadPart = m_offset + m_relativePosition + move.QuadPart;
|
||||
newPos.QuadPart = m_relativePosition + move.QuadPart;
|
||||
break;
|
||||
case Reference::START:
|
||||
newPos.QuadPart = m_offset + move.QuadPart;
|
||||
newPos.QuadPart = move.QuadPart;
|
||||
break;
|
||||
case Reference::END:
|
||||
newPos.QuadPart = m_offset + m_size + move.QuadPart;
|
||||
newPos.QuadPart = m_size + move.QuadPart;
|
||||
break;
|
||||
}
|
||||
//TODO: We need to constrain newPos so that it can't exceed the end of the stream
|
||||
|
||||
// Constrain newPos to range relative values
|
||||
if (newPos.QuadPart < 0)
|
||||
{
|
||||
newPos.QuadPart = 0;
|
||||
}
|
||||
else if (static_cast<uint64_t>(newPos.QuadPart) > m_size)
|
||||
{
|
||||
newPos.QuadPart = m_size;
|
||||
}
|
||||
|
||||
// Add in the underlying stream offset
|
||||
newPos.QuadPart += m_offset;
|
||||
|
||||
ULARGE_INTEGER pos = { 0 };
|
||||
m_stream->Seek(newPos, Reference::START, &pos);
|
||||
ThrowHrIfFailed(m_stream->Seek(newPos, Reference::START, &pos));
|
||||
m_relativePosition = std::min(static_cast<std::uint64_t>(pos.QuadPart - m_offset), m_size);
|
||||
if (newPosition) { newPosition->QuadPart = m_relativePosition; }
|
||||
return static_cast<HRESULT>(Error::OK);
|
||||
|
@ -68,7 +81,7 @@ namespace MSIX {
|
|||
ULONG amountToRead = std::min(countBytes, static_cast<ULONG>(m_size - m_relativePosition));
|
||||
ULONG amountRead = 0;
|
||||
ThrowHrIfFailed(m_stream->Read(buffer, amountToRead, &amountRead));
|
||||
ThrowErrorIf(Error::FileRead, (amountToRead != amountRead), "Did not read as much as requesteed.");
|
||||
ThrowErrorIf(Error::FileRead, (amountToRead != amountRead), "Did not read as much as requested.");
|
||||
m_relativePosition += amountRead;
|
||||
if (bytesRead) { *bytesRead = amountRead; }
|
||||
ThrowErrorIf(Error::FileSeekOutOfRange, (m_relativePosition > m_size), "seek pointer out of bounds.");
|
||||
|
@ -78,12 +91,15 @@ namespace MSIX {
|
|||
HRESULT STDMETHODCALLTYPE Write(const void *buffer, ULONG countBytes, ULONG *bytesWritten) noexcept override try
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
// Forward to VectorStream/DeflateStream
|
||||
ThrowHrIfFailed(m_stream->Write(buffer, countBytes, bytesWritten));
|
||||
m_size = static_cast<ULONG>(m_buffer.size());
|
||||
m_relativePosition = m_size;
|
||||
// VectorStream will validate if the written bytes are correct.
|
||||
// It is expected that countBytes != bytesWritten here because this can be a compression.
|
||||
LARGE_INTEGER offset = { 0 };
|
||||
offset.QuadPart = m_relativePosition + m_offset;
|
||||
ThrowHrIfFailed(m_stream->Seek(offset, StreamBase::START, nullptr));
|
||||
ULONG amountWritten = 0;
|
||||
ThrowHrIfFailed(m_stream->Write(buffer, countBytes, &amountWritten));
|
||||
ThrowErrorIf(Error::FileWrite, (countBytes != amountWritten), "Did not write as much as requested.");
|
||||
m_relativePosition += amountWritten;
|
||||
m_size = std::max(m_size, m_relativePosition);
|
||||
if (bytesWritten) { *bytesWritten = amountWritten; }
|
||||
return static_cast<HRESULT>(Error::OK);
|
||||
} CATCH_RETURN();
|
||||
|
||||
|
@ -94,7 +110,5 @@ namespace MSIX {
|
|||
std::uint64_t m_size;
|
||||
std::uint64_t m_relativePosition = 0;
|
||||
ComPtr<IStream> m_stream;
|
||||
// for pack, this is buffer were store the data, before writing it to the zip file
|
||||
std::vector<std::uint8_t> m_buffer;
|
||||
};
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "AppxPackaging.hpp"
|
||||
#include "Exceptions.hpp"
|
||||
#include "StreamBase.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
@ -56,5 +57,39 @@ namespace MSIX {
|
|||
ThrowHrIfFailed(stream->Write(static_cast<const void*>(toWrite.data()), static_cast<ULONG>(toWrite.size()), &written));
|
||||
ThrowErrorIf(Error::FileWrite, (static_cast<ULONG>(toWrite.size()) != written), "write failed");
|
||||
}
|
||||
|
||||
// Reverts a stream's position on destruction
|
||||
struct StreamPositionReset
|
||||
{
|
||||
StreamPositionReset(IStream* stream) : m_stream(stream)
|
||||
{
|
||||
ThrowHrIfFailed(m_stream->Seek({ 0 }, StreamBase::Reference::CURRENT, &m_pos));
|
||||
}
|
||||
|
||||
~StreamPositionReset()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
LARGE_INTEGER target;
|
||||
target.QuadPart = static_cast<LONGLONG>(m_pos.QuadPart);
|
||||
ThrowHrIfFailed(m_stream->Seek(target, StreamBase::Reference::START, nullptr));
|
||||
m_stream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
m_stream = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
ComPtr<IStream> m_stream;
|
||||
ULARGE_INTEGER m_pos;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -58,7 +58,12 @@ namespace MSIX {
|
|||
ThrowErrorIf(Error::FileWrite, expected != m_offset, "Error writing to stream");
|
||||
if (bytesWritten) { *bytesWritten = countBytes; }
|
||||
return static_cast<HRESULT>(Error::OK);
|
||||
} CATCH_RETURN();
|
||||
} CATCH_RETURN();
|
||||
|
||||
std::uint64_t GetSize() override
|
||||
{
|
||||
return static_cast<std::uint64_t>(m_data->size());
|
||||
}
|
||||
|
||||
protected:
|
||||
ULONG m_offset = 0;
|
||||
|
|
|
@ -24,16 +24,17 @@ namespace MSIX {
|
|||
bool isCompressed,
|
||||
std::uint64_t offset,
|
||||
std::uint64_t size,
|
||||
const ComPtr<IStream>& stream // this is the actual zip file stream
|
||||
) : m_isCompressed(isCompressed), RangeStream(offset, size, stream), m_name(name)
|
||||
IStream* stream // this is the actual zip file stream
|
||||
) : m_isCompressed(isCompressed), RangeStream(offset, size, stream), m_name(std::move(name))
|
||||
{
|
||||
}
|
||||
|
||||
// Represents an stream to be added to the zip file (pack)
|
||||
ZipFileStream(
|
||||
const std::string& name,
|
||||
bool isCompressed
|
||||
) : m_isCompressed(isCompressed), m_name(name), RangeStream(isCompressed)
|
||||
std::string name,
|
||||
bool isCompressed,
|
||||
IStream* stream
|
||||
) : m_isCompressed(isCompressed), m_name(std::move(name)), RangeStream(stream)
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
}
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
|
||||
namespace MSIX {
|
||||
|
||||
enum class ZipVersions : std::uint16_t
|
||||
{
|
||||
Zip32DefaultVersion = 20,
|
||||
Zip64FormatExtension = 45,
|
||||
};
|
||||
|
||||
enum class GeneralPurposeBitFlags : std::uint16_t
|
||||
{
|
||||
UNSUPPORTED_0 = 0x0001, // Bit 0: If set, indicates that the file is encrypted.
|
||||
|
@ -23,7 +29,7 @@ namespace MSIX {
|
|||
Deflate_MaxCompress = 0x0002, // Maximum compression (-exx/-ex), otherwise, normal compression (-en)
|
||||
Deflate_FastCompress = 0x0004, // Fast (-ef), if Max+Fast then SuperFast (-es) compression
|
||||
|
||||
GeneralPurposeBit = 0x0008, // the field's crc-32 compressed and uncompressed sizes = 0 in the local header
|
||||
DataDescriptor = 0x0008, // the field's crc-32 compressed and uncompressed sizes = 0 in the local header
|
||||
// the correct values are put in the data descriptor immediately following the
|
||||
// compressed data.
|
||||
EnhancedDeflate = 0x0010,
|
||||
|
@ -52,6 +58,11 @@ namespace MSIX {
|
|||
return static_cast<GeneralPurposeBitFlags>(static_cast<uint16_t>(a) | static_cast<uint16_t>(b));
|
||||
}
|
||||
|
||||
constexpr GeneralPurposeBitFlags operator ~(GeneralPurposeBitFlags a)
|
||||
{
|
||||
return static_cast<GeneralPurposeBitFlags>(~static_cast<uint16_t>(a));
|
||||
}
|
||||
|
||||
enum class CompressionType : std::uint16_t
|
||||
{
|
||||
Store = 0,
|
||||
|
@ -69,37 +80,61 @@ namespace MSIX {
|
|||
EndOfCentralDirectory = 0x06054b50,
|
||||
};
|
||||
|
||||
constexpr uint64_t MaxSizeToNotUseDataDescriptor = static_cast<uint64_t>(std::numeric_limits<std::uint32_t>::max() - 1);
|
||||
|
||||
template <typename T>
|
||||
inline bool IsValueInExtendedInfo(T value) noexcept
|
||||
{
|
||||
return (value == std::numeric_limits<T>::max());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool IsValueInExtendedInfo(const Meta::FieldBase<T>& field) noexcept
|
||||
{
|
||||
return IsValueInExtendedInfo(field.get());
|
||||
}
|
||||
|
||||
class Zip64ExtendedInformation final : public Meta::StructuredObject<
|
||||
Meta::Field2Bytes, // 0 - tag for the "extra" block type 2 bytes(0x0001)
|
||||
Meta::Field2Bytes, // 1 - size of this "extra" block 2 bytes
|
||||
Meta::Field8Bytes, // 2 - Original uncompressed file size 8 bytes
|
||||
// No point in validating these as it is actually
|
||||
// possible to have a 0-byte file... Who knew.
|
||||
Meta::Field8Bytes, // 3 - Compressed file size 8 bytes
|
||||
// No point in validating these as it is actually
|
||||
// possible to have a 0-byte file... Who knew.
|
||||
Meta::Field8Bytes // 4 - Offset of local header record 8 bytes
|
||||
//Meta::Field4Bytes // 5 - number of the disk on which the file starts 4 bytes -- ITS A FAAKEE!
|
||||
Meta::Field2Bytes, // 0 - tag for the "extra" block type 2 bytes(0x0001)
|
||||
Meta::Field2Bytes, // 1 - size of this "extra" block 2 bytes
|
||||
Meta::OptionalField8Bytes, // 2 - Original uncompressed file size 8 bytes
|
||||
Meta::OptionalField8Bytes, // 3 - Compressed file size 8 bytes
|
||||
Meta::OptionalField8Bytes, // 4 - Offset of local header record 8 bytes
|
||||
Meta::OptionalField4Bytes // 5 - number of the disk on which the file starts 4 bytes
|
||||
>
|
||||
{
|
||||
public:
|
||||
Zip64ExtendedInformation();
|
||||
|
||||
void SetData(std::uint64_t uncompressedSize, std::uint64_t compressedSize, std::uint64_t relativeOffset);
|
||||
// The incoming values are those from the central directory record. Their value there determines
|
||||
// whether we attempt to read them here.
|
||||
void Read(const ComPtr<IStream>& stream, ULARGE_INTEGER start, uint32_t uncompressedSize, uint32_t compressedSize, uint32_t offset, uint16_t disk);
|
||||
|
||||
void Read(const ComPtr<IStream>& stream, ULARGE_INTEGER start);
|
||||
std::uint64_t GetUncompressedSize() const { return Field<2>(); }
|
||||
std::uint64_t GetCompressedSize() const { return Field<3>(); }
|
||||
std::uint64_t GetRelativeOffsetOfLocalHeader() const { return Field<4>(); }
|
||||
std::uint32_t GetDiskStartNumber() const { return Field<5>(); }
|
||||
|
||||
std::uint64_t GetUncompressedSize() noexcept { return Field<2>().value; }
|
||||
std::uint64_t GetCompressedSize() noexcept { return Field<3>().value; }
|
||||
std::uint64_t GetRelativeOffsetOfLocalHeader() noexcept { return Field<4>().value; }
|
||||
void SetUncompressedSize(std::uint64_t value) noexcept { Field<2>() = value; }
|
||||
void SetCompressedSize(std::uint64_t value) noexcept { Field<3>() = value; }
|
||||
void SetRelativeOffsetOfLocalHeader(std::uint64_t value) noexcept { Field<4>() = value; }
|
||||
|
||||
bool HasAnySet() const
|
||||
{
|
||||
return (Field<2>() || Field<3>() || Field<4>() || Field<5>());
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> GetBytes()
|
||||
{
|
||||
SetSize(static_cast<uint16_t>(Size() - NonOptionalSize));
|
||||
return StructuredObject::GetBytes();
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetSignature(std::uint16_t value) noexcept { Field<0>().value = value; }
|
||||
void SetSize(std::uint16_t value) noexcept { Field<1>().value = value; }
|
||||
void SetUncompressedSize(std::uint64_t value) noexcept { Field<2>().value = value; }
|
||||
void SetCompressedSize(std::uint64_t value) noexcept { Field<3>().value = value; }
|
||||
void SetRelativeOffsetOfLocalHeader(std::uint64_t value) noexcept { Field<4>().value = value; }
|
||||
constexpr static size_t NonOptionalSize = 4;
|
||||
|
||||
void SetSignature(std::uint16_t value) noexcept { Field<0>() = value; }
|
||||
void SetSize(std::uint16_t value) noexcept { Field<1>() = value; }
|
||||
};
|
||||
|
||||
class CentralDirectoryFileHeader final : public Meta::StructuredObject<
|
||||
|
@ -128,81 +163,125 @@ namespace MSIX {
|
|||
public:
|
||||
CentralDirectoryFileHeader();
|
||||
|
||||
void SetData(std::string& name, std::uint32_t crc, std::uint64_t compressedSize,
|
||||
std::uint64_t uncompressedSize, std::uint64_t relativeOffset, std::uint16_t compressionMethod);
|
||||
void SetData(const std::string& name, std::uint32_t crc, std::uint64_t compressedSize,
|
||||
std::uint64_t uncompressedSize, std::uint64_t relativeOffset, std::uint16_t compressionMethod, bool forceDataDescriptor);
|
||||
|
||||
void Read(const ComPtr<IStream>& stream, bool isZip64);
|
||||
|
||||
bool IsGeneralPurposeBitSet() noexcept
|
||||
GeneralPurposeBitFlags GetGeneralPurposeBitFlags() const noexcept { return static_cast<GeneralPurposeBitFlags>(Field<3>().get()); }
|
||||
|
||||
bool IsGeneralPurposeBitSet() const noexcept
|
||||
{
|
||||
return ((static_cast<GeneralPurposeBitFlags>(Field<3>().value) & GeneralPurposeBitFlags::GeneralPurposeBit) == GeneralPurposeBitFlags::GeneralPurposeBit);
|
||||
return ((GetGeneralPurposeBitFlags() & GeneralPurposeBitFlags::DataDescriptor) == GeneralPurposeBitFlags::DataDescriptor);
|
||||
}
|
||||
|
||||
CompressionType GetCompressionMethod() noexcept { return static_cast<CompressionType>(Field<4>().value); }
|
||||
CompressionType GetCompressionMethod() const noexcept { return static_cast<CompressionType>(Field<4>().get()); }
|
||||
|
||||
std::uint64_t GetCompressedSize() noexcept
|
||||
std::uint64_t GetCompressedSize() const noexcept
|
||||
{
|
||||
if (m_isZip64)
|
||||
if (IsValueInExtendedInfo(Field<8>()))
|
||||
{
|
||||
return m_extendedInfo.GetCompressedSize();
|
||||
}
|
||||
return static_cast<std::uint64_t>(Field<8>().value);
|
||||
return static_cast<std::uint64_t>(Field<8>().get());
|
||||
}
|
||||
|
||||
std::uint64_t GetUncompressedSize() noexcept
|
||||
std::uint64_t GetUncompressedSize() const noexcept
|
||||
{
|
||||
if (m_isZip64)
|
||||
if (IsValueInExtendedInfo(Field<9>()))
|
||||
{
|
||||
return m_extendedInfo.GetUncompressedSize();
|
||||
}
|
||||
return static_cast<std::uint64_t>(Field<9>().value);
|
||||
return static_cast<std::uint64_t>(Field<9>().get());
|
||||
}
|
||||
|
||||
std::uint64_t GetRelativeOffsetOfLocalHeader() noexcept
|
||||
std::uint64_t GetRelativeOffsetOfLocalHeader() const noexcept
|
||||
{
|
||||
if (m_isZip64)
|
||||
if (IsValueInExtendedInfo(Field<16>()))
|
||||
{
|
||||
return m_extendedInfo.GetRelativeOffsetOfLocalHeader();
|
||||
|
||||
}
|
||||
return static_cast<std::uint64_t>(Field<16>().value);
|
||||
return static_cast<std::uint64_t>(Field<16>().get());
|
||||
}
|
||||
|
||||
std::string GetFileName()
|
||||
std::string GetFileName() const
|
||||
{
|
||||
auto data = Field<17>().value;
|
||||
auto data = Field<17>().get();
|
||||
return std::string(data.begin(), data.end());
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>().value = value; }
|
||||
void SetVersionMadeBy(std::uint16_t value) noexcept { Field<1>().value = value; }
|
||||
void SetVersionNeededToExtract(std::uint16_t value) noexcept { Field<2>().value = value; }
|
||||
void SetGeneralPurposeBitFlags(std::uint16_t value) noexcept { Field<3>().value = value; }
|
||||
void SetCompressionMethod(std::uint16_t value) noexcept { Field<4>().value = value; }
|
||||
void SetLastModFileTime(std::uint16_t value) noexcept { Field<5>().value = value; }
|
||||
void SetLastModFileDate(std::uint16_t value) noexcept { Field<6>().value = value; }
|
||||
void SetCrc(std::uint32_t value) noexcept { Field<7>().value = value; }
|
||||
void SetCompressedSize(std::uint32_t value) noexcept { Field<8>().value = value; }
|
||||
void SetUncompressedSize(std::uint32_t value) noexcept { Field<9>().value = value; }
|
||||
void SetFileNameLength(std::uint16_t value) noexcept { Field<10>().value = value; }
|
||||
void SetExtraFieldLength(std::uint16_t value) noexcept { Field<11>().value = value; }
|
||||
void SetFileCommentLength(std::uint16_t value) noexcept { Field<12>().value = value; }
|
||||
void SetDiskNumberStart(std::uint16_t value) noexcept { Field<13>().value = value; }
|
||||
void SetInternalFileAttributes(std::uint16_t value) noexcept { Field<14>().value = value; }
|
||||
void SetExternalFileAttributes(std::uint16_t value) noexcept { Field<15>().value = value; }
|
||||
void SetRelativeOffsetOfLocalHeader(std::uint32_t value) noexcept { Field<16>().value = value; }
|
||||
void SetFileName(std::string& name)
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>() = value; }
|
||||
void SetVersionMadeBy(std::uint16_t value) noexcept { Field<1>() = value; }
|
||||
void SetVersionNeededToExtract(std::uint16_t value) noexcept { Field<2>() = value; }
|
||||
void SetGeneralPurposeBitFlags(std::uint16_t value) noexcept { Field<3>() = value; }
|
||||
void SetCompressionMethod(std::uint16_t value) noexcept { Field<4>() = value; }
|
||||
void SetLastModFileTime(std::uint16_t value) noexcept { Field<5>() = value; }
|
||||
void SetLastModFileDate(std::uint16_t value) noexcept { Field<6>() = value; }
|
||||
void SetCrc(std::uint32_t value) noexcept { Field<7>() = value; }
|
||||
void SetFileNameLength(std::uint16_t value) noexcept { Field<10>() = value; }
|
||||
void SetExtraFieldLength(std::uint16_t value) noexcept { Field<11>() = value; }
|
||||
void SetFileCommentLength(std::uint16_t value) noexcept { Field<12>() = value; }
|
||||
void SetDiskNumberStart(std::uint16_t value) noexcept { Field<13>() = value; }
|
||||
void SetInternalFileAttributes(std::uint16_t value) noexcept { Field<14>() = value; }
|
||||
void SetExternalFileAttributes(std::uint16_t value) noexcept { Field<15>() = value; }
|
||||
|
||||
// Values that might appear in the extended info (minus disk, which we will never set there)
|
||||
void SetCompressedSize(std::uint64_t value) noexcept
|
||||
{
|
||||
if (value > MaxSizeToNotUseDataDescriptor)
|
||||
{
|
||||
m_extendedInfo.SetCompressedSize(value);
|
||||
Field<8>() = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
Field<8>() = static_cast<uint32_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
void SetUncompressedSize(std::uint64_t value)noexcept
|
||||
{
|
||||
if (value > MaxSizeToNotUseDataDescriptor)
|
||||
{
|
||||
m_extendedInfo.SetUncompressedSize(value);
|
||||
Field<9>() = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
Field<9>() = static_cast<uint32_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
void SetRelativeOffsetOfLocalHeader(std::uint64_t value) noexcept
|
||||
{
|
||||
if (value > MaxSizeToNotUseDataDescriptor)
|
||||
{
|
||||
m_extendedInfo.SetRelativeOffsetOfLocalHeader(value);
|
||||
Field<16>() = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
Field<16>() = static_cast<uint32_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
void SetFileName(const std::string& name)
|
||||
{
|
||||
SetFileNameLength(static_cast<std::uint16_t>(name.size()));
|
||||
Field<17>().value.resize(name.size(), 0);
|
||||
std::copy(name.begin(), name.end(), Field<17>().value.begin());
|
||||
Field<17>().get().resize(name.size(), 0);
|
||||
std::copy(name.begin(), name.end(), Field<17>().get().begin());
|
||||
}
|
||||
void SetExtraField(std::uint64_t compressedSize, std::uint64_t uncompressedSize, std::uint64_t relativeOffset)
|
||||
|
||||
void UpdateExtraField()
|
||||
{
|
||||
m_extendedInfo.SetData(compressedSize, uncompressedSize, relativeOffset);
|
||||
SetExtraFieldLength(static_cast<std::uint16_t>(m_extendedInfo.Size()));
|
||||
Field<18>().value = m_extendedInfo.GetBytes();
|
||||
if (m_extendedInfo.HasAnySet())
|
||||
{
|
||||
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
SetExtraFieldLength(static_cast<std::uint16_t>(m_extendedInfo.Size()));
|
||||
Field<18>().get() = m_extendedInfo.GetBytes();
|
||||
}
|
||||
}
|
||||
|
||||
Zip64ExtendedInformation m_extendedInfo;
|
||||
|
@ -228,40 +307,42 @@ namespace MSIX {
|
|||
public:
|
||||
LocalFileHeader();
|
||||
|
||||
void SetData(std::string& name, bool isCompressed);
|
||||
void SetData(const std::string& name, bool isCompressed);
|
||||
void SetData(std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize);
|
||||
|
||||
void Read(const ComPtr<IStream>& stream, CentralDirectoryFileHeader& directoryEntry);
|
||||
|
||||
std::uint16_t GetCompressionMethod() noexcept { return Field<3>().value; }
|
||||
std::uint16_t GetFileNameLength() noexcept { return Field<9>().value; }
|
||||
std::string GetFileName()
|
||||
GeneralPurposeBitFlags GetGeneralPurposeBitFlags() const noexcept { return static_cast<GeneralPurposeBitFlags>(Field<2>().get()); }
|
||||
std::uint16_t GetCompressionMethod() const noexcept { return Field<3>(); }
|
||||
std::uint16_t GetFileNameLength() const noexcept { return Field<9>(); }
|
||||
std::string GetFileName() const
|
||||
{
|
||||
auto data = Field<11>().value;
|
||||
auto data = Field<11>().get();
|
||||
return std::string(data.begin(), data.end());
|
||||
}
|
||||
|
||||
protected:
|
||||
bool IsGeneralPurposeBitSet() noexcept
|
||||
bool IsGeneralPurposeBitSet() const noexcept
|
||||
{
|
||||
return ((static_cast<GeneralPurposeBitFlags>(Field<2>().value) & GeneralPurposeBitFlags::GeneralPurposeBit) == GeneralPurposeBitFlags::GeneralPurposeBit);
|
||||
return ((GetGeneralPurposeBitFlags() & GeneralPurposeBitFlags::DataDescriptor) == GeneralPurposeBitFlags::DataDescriptor);
|
||||
}
|
||||
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>().value = value; }
|
||||
void SetVersionNeededToExtract(std::uint16_t value) noexcept { Field<1>().value = value; }
|
||||
void SetGeneralPurposeBitFlags(std::uint16_t value) noexcept { Field<2>().value = value; }
|
||||
void SetCompressionMethod(std::uint16_t value) noexcept { Field<3>().value = value; }
|
||||
void SetLastModFileTime(std::uint16_t value) noexcept { Field<4>().value = value; }
|
||||
void SetLastModFileDate(std::uint16_t value) noexcept { Field<5>().value = value; }
|
||||
void SetCrc(std::uint32_t value) noexcept { Field<6>().value = value; }
|
||||
void SetCompressedSize(std::uint32_t value) noexcept { Field<7>().value = value; }
|
||||
void SetUncompressedSize(std::uint32_t value) noexcept { Field<8>().value = value; }
|
||||
void SetFileNameLength(std::uint16_t value) noexcept { Field<9>().value = value; }
|
||||
void SetExtraFieldLength(std::uint16_t value) noexcept { Field<10>().value = value; }
|
||||
void SetFileName(std::string& name)
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>() = value; }
|
||||
void SetVersionNeededToExtract(std::uint16_t value) noexcept { Field<1>() = value; }
|
||||
void SetGeneralPurposeBitFlags(std::uint16_t value) noexcept { Field<2>() = value; }
|
||||
void SetCompressionMethod(std::uint16_t value) noexcept { Field<3>() = value; }
|
||||
void SetLastModFileTime(std::uint16_t value) noexcept { Field<4>() = value; }
|
||||
void SetLastModFileDate(std::uint16_t value) noexcept { Field<5>() = value; }
|
||||
void SetCrc(std::uint32_t value) noexcept { Field<6>() = value; }
|
||||
void SetCompressedSize(std::uint32_t value) noexcept { Field<7>() = value; }
|
||||
void SetUncompressedSize(std::uint32_t value) noexcept { Field<8>() = value; }
|
||||
void SetFileNameLength(std::uint16_t value) noexcept { Field<9>() = value; }
|
||||
void SetExtraFieldLength(std::uint16_t value) noexcept { Field<10>() = value; }
|
||||
void SetFileName(const std::string& name)
|
||||
{
|
||||
SetFileNameLength(static_cast<std::uint16_t>(name.size()));
|
||||
Field<11>().value.resize(name.size(), 0);
|
||||
std::copy(name.begin(), name.end(), Field<11>().value.begin());
|
||||
Field<11>().get().resize(name.size(), 0);
|
||||
std::copy(name.begin(), name.end(), Field<11>().get().begin());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -287,23 +368,23 @@ namespace MSIX {
|
|||
|
||||
void Read(const ComPtr<IStream>& stream);
|
||||
|
||||
std::uint64_t GetTotalNumberOfEntries() noexcept { return Field<6>().value; }
|
||||
std::uint64_t GetOffsetStartOfCD() noexcept { return Field<9>().value; }
|
||||
std::uint64_t GetTotalNumberOfEntries() const noexcept { return Field<6>(); }
|
||||
std::uint64_t GetOffsetStartOfCD() const noexcept { return Field<9>(); }
|
||||
|
||||
protected:
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>().value = value; }
|
||||
void SetSizeOfZip64CDRecord(std::uint64_t value) noexcept { Field<1>().value = value; }
|
||||
void SetVersionMadeBy(std::uint16_t value) noexcept { Field<2>().value = value; }
|
||||
void SetVersionNeededToExtract(std::uint16_t value) noexcept { Field<3>().value = value; }
|
||||
void SetNumberOfThisDisk(std::uint32_t value) noexcept { Field<4>().value = value; }
|
||||
void SetNumberOfTheDiskWithStartOfCD(std::uint32_t value) noexcept { Field<5>().value = value; }
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>() = value; }
|
||||
void SetSizeOfZip64CDRecord(std::uint64_t value) noexcept { Field<1>() = value; }
|
||||
void SetVersionMadeBy(std::uint16_t value) noexcept { Field<2>() = value; }
|
||||
void SetVersionNeededToExtract(std::uint16_t value) noexcept { Field<3>() = value; }
|
||||
void SetNumberOfThisDisk(std::uint32_t value) noexcept { Field<4>() = value; }
|
||||
void SetNumberOfTheDiskWithStartOfCD(std::uint32_t value) noexcept { Field<5>() = value; }
|
||||
void SetTotalNumberOfEntriesDisk(std::uint64_t value) noexcept
|
||||
{
|
||||
Field<6>().value = value;
|
||||
Field<7>().value = value;
|
||||
Field<6>() = value;
|
||||
Field<7>() = value;
|
||||
}
|
||||
void SetSizeOfCD(std::uint64_t value) noexcept { Field<8>().value = value; }
|
||||
void SetOffsetfStartOfCD(std::uint64_t value) noexcept { Field<9>().value = value; }
|
||||
void SetSizeOfCD(std::uint64_t value) noexcept { Field<8>() = value; }
|
||||
void SetOffsetfStartOfCD(std::uint64_t value) noexcept { Field<9>() = value; }
|
||||
};
|
||||
|
||||
class Zip64EndOfCentralDirectoryLocator final : public Meta::StructuredObject<
|
||||
|
@ -322,13 +403,13 @@ namespace MSIX {
|
|||
|
||||
void Read(const ComPtr<IStream>& stream);
|
||||
|
||||
std::uint64_t GetRelativeOffset() noexcept { return Field<2>().value; }
|
||||
std::uint64_t GetRelativeOffset() const noexcept { return Field<2>(); }
|
||||
|
||||
protected:
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>().value = value; }
|
||||
void SetNumberOfDisk(std::uint32_t value) noexcept { Field<1>().value = value; }
|
||||
void SetRelativeOffset(std::uint64_t value) noexcept { Field<2>().value = value; }
|
||||
void SetTotalNumberOfDisks(std::uint32_t value) noexcept { Field<3>().value = value; }
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>() = value; }
|
||||
void SetNumberOfDisk(std::uint32_t value) noexcept { Field<1>() = value; }
|
||||
void SetRelativeOffset(std::uint64_t value) noexcept { Field<2>() = value; }
|
||||
void SetTotalNumberOfDisks(std::uint32_t value) noexcept { Field<3>() = value; }
|
||||
};
|
||||
|
||||
class EndCentralDirectoryRecord final : public Meta::StructuredObject<
|
||||
|
@ -352,24 +433,22 @@ namespace MSIX {
|
|||
|
||||
void Read(const ComPtr<IStream>& stream);
|
||||
|
||||
bool GetArchiveHasZip64Locator() noexcept { return m_archiveHasZip64Locator; }
|
||||
bool GetIsZip64() noexcept { return m_isZip64; }
|
||||
bool GetIsZip64() const noexcept { return m_isZip64; }
|
||||
|
||||
std::uint64_t GetNumberOfCentralDirectoryEntries() noexcept { return static_cast<std::uint64_t>(Field<3>().value); }
|
||||
std::uint64_t GetStartOfCentralDirectory() noexcept { return static_cast<std::uint64_t>(Field<6>().value); }
|
||||
std::uint64_t GetNumberOfCentralDirectoryEntries() noexcept { return static_cast<std::uint64_t>(Field<3>().get()); }
|
||||
std::uint64_t GetStartOfCentralDirectory() noexcept { return static_cast<std::uint64_t>(Field<6>().get()); }
|
||||
|
||||
protected:
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>().value = value; }
|
||||
void SetNumberOfDisk(std::uint16_t value) noexcept { Field<1>().value = value; }
|
||||
void SetDiskStart(std::uint16_t value) noexcept { Field<2>().value = value; }
|
||||
void SetTotalNumberOfEntries(std::uint16_t value) noexcept { Field<3>().value = value; }
|
||||
void SetTotalEntriesInCentralDirectory(std::uint16_t value) noexcept { Field<4>().value = value; }
|
||||
void SetSizeOfCentralDirectory(std::uint32_t value) noexcept { Field<5>().value = value; }
|
||||
void SetOffsetOfCentralDirectory(std::uint32_t value) noexcept { Field<6>().value = value; }
|
||||
void SetCommentLength(std::uint16_t value) noexcept { Field<7>().value = value; }
|
||||
void SetSignature(std::uint32_t value) noexcept { Field<0>() = value; }
|
||||
void SetNumberOfDisk(std::uint16_t value) noexcept { Field<1>() = value; }
|
||||
void SetDiskStart(std::uint16_t value) noexcept { Field<2>() = value; }
|
||||
void SetTotalNumberOfEntries(std::uint16_t value) noexcept { Field<3>() = value; }
|
||||
void SetTotalEntriesInCentralDirectory(std::uint16_t value) noexcept { Field<4>() = value; }
|
||||
void SetSizeOfCentralDirectory(std::uint32_t value) noexcept { Field<5>() = value; }
|
||||
void SetOffsetOfCentralDirectory(std::uint32_t value) noexcept { Field<6>() = value; }
|
||||
void SetCommentLength(std::uint16_t value) noexcept { Field<7>() = value; }
|
||||
|
||||
bool m_isZip64 = true;
|
||||
bool m_archiveHasZip64Locator = true;
|
||||
};
|
||||
|
||||
class ZipObject
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
// {350dd671-0c40-4cd7-9a5b-27456d604bd0}
|
||||
#ifndef WIN32
|
||||
|
@ -24,12 +25,11 @@ class IZipWriter : public IUnknown
|
|||
{
|
||||
public:
|
||||
// Writes the lfh header to the stream and return the size of the header
|
||||
virtual std::uint32_t PrepareToAddFile(std::string& name, bool isCompressed) = 0;
|
||||
virtual std::pair<std::uint32_t, MSIX::ComPtr<IStream>> PrepareToAddFile(const std::string& name, bool isCompressed) = 0;
|
||||
|
||||
// Writes the stream provided to the zip file, writes data descriptor and adds an entry
|
||||
// Ends the file, rewrites the LFH or writes data descriptor and adds an entry
|
||||
// to the central directories map
|
||||
virtual void AddFile(MSIX::ComPtr<IStream>& fileStream, std::uint32_t crc,
|
||||
std::uint64_t compressedSize, std::uint64_t uncompressedSize) = 0;
|
||||
virtual void EndFile(std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize, bool forceDataDescriptor) = 0;
|
||||
|
||||
// Ends zip file by writing the central directory records, zip64 locator,
|
||||
// zip64 end of central directory and the end of central directories.
|
||||
|
@ -52,9 +52,8 @@ namespace MSIX {
|
|||
std::string GetFileName() override { NOTIMPLEMENTED };
|
||||
|
||||
// IZipWriter
|
||||
std::uint32_t PrepareToAddFile(std::string& name, bool isCompressed) override;
|
||||
void AddFile(MSIX::ComPtr<IStream>& fileStream, std::uint32_t crc,
|
||||
std::uint64_t compressedSize, std::uint64_t uncompressedSize) override;
|
||||
std::pair<std::uint32_t, ComPtr<IStream>> PrepareToAddFile(const std::string& name, bool isCompressed) override;
|
||||
void EndFile(std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize, bool forceDataDescriptor) override;
|
||||
void Close() override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -37,11 +37,6 @@ namespace MSIX {
|
|||
[Zip64EndOfCentralDirectoryLocator]
|
||||
[EndCentralDirectoryRecord]
|
||||
*/
|
||||
enum class ZipVersions : std::uint16_t
|
||||
{
|
||||
Zip32DefaultVersion = 20,
|
||||
Zip64FormatExtension = 45,
|
||||
};
|
||||
|
||||
// from AppNote.txt, section 4.5.2:
|
||||
enum class HeaderIDs : std::uint16_t
|
||||
|
@ -98,31 +93,38 @@ constexpr static const GeneralPurposeBitFlags UnsupportedFlagsMask =
|
|||
Zip64ExtendedInformation::Zip64ExtendedInformation()
|
||||
{
|
||||
SetSignature(static_cast<std::uint16_t>(HeaderIDs::Zip64ExtendedInfo));
|
||||
// Should be 0x18, but do it this way if we end up field 5
|
||||
SetSize(static_cast<std::uint16_t>(Size() - Field<0>().Size() - Field<1>().Size()));
|
||||
SetSize(NonOptionalSize);
|
||||
}
|
||||
|
||||
void Zip64ExtendedInformation::SetData(std::uint64_t uncompressedSize, std::uint64_t compressedSize, std::uint64_t relativeOffset)
|
||||
void Zip64ExtendedInformation::Read(const ComPtr<IStream>& stream, ULARGE_INTEGER start, uint32_t uncompressedSize, uint32_t compressedSize, uint32_t offset, uint16_t disk)
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
SetUncompressedSize(uncompressedSize);
|
||||
SetCompressedSize(compressedSize);
|
||||
SetRelativeOffsetOfLocalHeader(relativeOffset);
|
||||
}
|
||||
StreamBase::Read(stream, &Field<0>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>(), static_cast<std::uint32_t>(HeaderIDs::Zip64ExtendedInfo));
|
||||
|
||||
void Zip64ExtendedInformation::Read(const ComPtr<IStream>& stream, ULARGE_INTEGER start)
|
||||
{
|
||||
StreamBase::Read(stream, &Field<0>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>().value, static_cast<std::uint32_t>(HeaderIDs::Zip64ExtendedInfo));
|
||||
StreamBase::Read(stream, &Field<1>());
|
||||
// The incoming stream will be just the extended info, and our size should match it minus the fixed bytes
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<1>(), static_cast<uint32_t>(stream.As<IStreamInternal>()->GetSize() - NonOptionalSize));
|
||||
|
||||
StreamBase::Read(stream, &Field<1>().value);
|
||||
Meta::OnlyEitherValueValidation<std::uint32_t>(Field<1>().value, 24, 28);
|
||||
|
||||
StreamBase::Read(stream, &Field<2>().value);
|
||||
StreamBase::Read(stream, &Field<3>().value);
|
||||
if (IsValueInExtendedInfo(uncompressedSize))
|
||||
{
|
||||
StreamBase::Read(stream, &Field<2>());
|
||||
}
|
||||
|
||||
StreamBase::Read(stream, &Field<4>().value);
|
||||
ThrowErrorIfNot(Error::ZipBadExtendedData, Field<4>().value < start.QuadPart, "invalid relative header offset");
|
||||
if (IsValueInExtendedInfo(compressedSize))
|
||||
{
|
||||
StreamBase::Read(stream, &Field<3>());
|
||||
}
|
||||
|
||||
if (IsValueInExtendedInfo(offset))
|
||||
{
|
||||
StreamBase::Read(stream, &Field<4>());
|
||||
ThrowErrorIfNot(Error::ZipBadExtendedData, Field<4>().get() < start.QuadPart, "invalid relative header offset");
|
||||
}
|
||||
|
||||
if (IsValueInExtendedInfo(disk))
|
||||
{
|
||||
StreamBase::Read(stream, &Field<5>());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -132,104 +134,112 @@ CentralDirectoryFileHeader::CentralDirectoryFileHeader()
|
|||
{
|
||||
SetSignature(static_cast<std::uint32_t>(Signatures::CentralFileHeader));
|
||||
SetVersionMadeBy(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension)); // we always do zip64
|
||||
SetGeneralPurposeBitFlags(static_cast<std::uint16_t>(GeneralPurposeBitFlags::GeneralPurposeBit));
|
||||
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion));
|
||||
SetGeneralPurposeBitFlags(0);
|
||||
SetLastModFileDate(static_cast<std::uint16_t>(MagicNumbers::FileDate)); // TODO: figure out how to convert to msdos time
|
||||
SetLastModFileTime(static_cast<std::uint16_t>(MagicNumbers::FileTime));
|
||||
SetCompressedSize(std::numeric_limits<std::uint32_t>::max()); // always use zip64
|
||||
SetUncompressedSize(std::numeric_limits<std::uint32_t>::max()); // always use zip64
|
||||
SetCompressedSize(0);
|
||||
SetUncompressedSize(0);
|
||||
SetExtraFieldLength(0);
|
||||
SetFileCommentLength(0);
|
||||
SetDiskNumberStart(0);
|
||||
SetInternalFileAttributes(0);
|
||||
SetExternalFileAttributes(0);
|
||||
SetRelativeOffsetOfLocalHeader(std::numeric_limits<std::uint32_t>::max()); // always use zip64
|
||||
SetRelativeOffsetOfLocalHeader(0);
|
||||
}
|
||||
|
||||
void CentralDirectoryFileHeader::SetData(std::string& name, std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize,
|
||||
std::uint64_t relativeOffset, std::uint16_t compressionMethod)
|
||||
void CentralDirectoryFileHeader::SetData(const std::string& name, std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize,
|
||||
std::uint64_t relativeOffset, std::uint16_t compressionMethod, bool forceDataDescriptor)
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
SetCompressionMethod(compressionMethod);
|
||||
SetCrc(crc);
|
||||
SetFileName(name);
|
||||
SetExtraField(uncompressedSize, compressedSize, relativeOffset);
|
||||
|
||||
// Set these values that may end up in the extra field info; then make sure to update it
|
||||
SetCompressedSize(compressedSize);
|
||||
SetUncompressedSize(uncompressedSize);
|
||||
SetRelativeOffsetOfLocalHeader(relativeOffset);
|
||||
UpdateExtraField();
|
||||
|
||||
if (forceDataDescriptor ||
|
||||
compressedSize > MaxSizeToNotUseDataDescriptor ||
|
||||
uncompressedSize > MaxSizeToNotUseDataDescriptor)
|
||||
{
|
||||
SetGeneralPurposeBitFlags(static_cast<std::uint16_t>(GeneralPurposeBitFlags::DataDescriptor));
|
||||
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
}
|
||||
}
|
||||
|
||||
void CentralDirectoryFileHeader::Read(const ComPtr<IStream>& stream, bool isZip64)
|
||||
{
|
||||
m_isZip64 = isZip64;
|
||||
StreamBase::Read(stream, &Field<0>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>().value, static_cast<std::uint32_t>(Signatures::CentralFileHeader));
|
||||
StreamBase::Read(stream, &Field<0>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>(), static_cast<std::uint32_t>(Signatures::CentralFileHeader));
|
||||
|
||||
StreamBase::Read(stream, &Field<1>().value);
|
||||
StreamBase::Read(stream, &Field<2>().value);
|
||||
StreamBase::Read(stream, &Field<1>());
|
||||
StreamBase::Read(stream, &Field<2>());
|
||||
|
||||
StreamBase::Read(stream, &Field<3>().value);
|
||||
StreamBase::Read(stream, &Field<3>());
|
||||
ThrowErrorIfNot(Error::ZipCentralDirectoryHeader,
|
||||
0 == (Field<3>().value & static_cast<std::uint16_t>(UnsupportedFlagsMask)),
|
||||
0 == (Field<3>().get() & static_cast<std::uint16_t>(UnsupportedFlagsMask)),
|
||||
"unsupported flag(s) specified");
|
||||
|
||||
StreamBase::Read(stream, &Field<4>().value);
|
||||
Meta::OnlyEitherValueValidation<std::uint16_t>(Field<4>().value, static_cast<std::uint16_t>(CompressionType::Deflate),
|
||||
StreamBase::Read(stream, &Field<4>());
|
||||
Meta::OnlyEitherValueValidation<std::uint16_t>(Field<4>(), static_cast<std::uint16_t>(CompressionType::Deflate),
|
||||
static_cast<std::uint16_t>(CompressionType::Store));
|
||||
|
||||
StreamBase::Read(stream, &Field<5>().value);
|
||||
StreamBase::Read(stream, &Field<6>().value);
|
||||
StreamBase::Read(stream, &Field<7>().value);
|
||||
StreamBase::Read(stream, &Field<8>().value);
|
||||
StreamBase::Read(stream, &Field<9>().value);
|
||||
StreamBase::Read(stream, &Field<5>());
|
||||
StreamBase::Read(stream, &Field<6>());
|
||||
StreamBase::Read(stream, &Field<7>());
|
||||
StreamBase::Read(stream, &Field<8>());
|
||||
StreamBase::Read(stream, &Field<9>());
|
||||
|
||||
StreamBase::Read(stream, &Field<10>().value);
|
||||
ThrowErrorIfNot(Error::ZipCentralDirectoryHeader, (Field<10>().value != 0), "unsupported file name size");
|
||||
if (Field<10>().value !=0) {Field<17>().value.resize(Field<10>().value, 0); }
|
||||
StreamBase::Read(stream, &Field<10>());
|
||||
ThrowErrorIfNot(Error::ZipCentralDirectoryHeader, (Field<10>().get() != 0), "unsupported file name size");
|
||||
if (Field<10>().get() != 0) {Field<17>().get().resize(Field<10>().get(), 0); }
|
||||
|
||||
StreamBase::Read(stream, &Field<11>().value);
|
||||
if (Field<11>().value != 0) { Field<18>().value.resize(Field<11>().value, 0); }
|
||||
StreamBase::Read(stream, &Field<11>());
|
||||
if (Field<11>().get() != 0) { Field<18>().get().resize(Field<11>().get(), 0); }
|
||||
|
||||
StreamBase::Read(stream, &Field<12>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<12>().value, 0);
|
||||
StreamBase::Read(stream, &Field<12>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<12>(), 0);
|
||||
|
||||
StreamBase::Read(stream, &Field<13>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<13>().value, 0);
|
||||
StreamBase::Read(stream, &Field<13>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<13>(), 0);
|
||||
|
||||
StreamBase::Read(stream, &Field<14>().value);
|
||||
StreamBase::Read(stream, &Field<14>());
|
||||
|
||||
StreamBase::Read(stream, &Field<15>().value);
|
||||
StreamBase::Read(stream, &Field<16>().value);
|
||||
StreamBase::Read(stream, &Field<15>());
|
||||
StreamBase::Read(stream, &Field<16>());
|
||||
ULARGE_INTEGER pos = {0};
|
||||
ThrowHrIfFailed(stream->Seek({0}, StreamBase::Reference::CURRENT, &pos));
|
||||
if (m_isZip64)
|
||||
if (!m_isZip64 || !IsValueInExtendedInfo(Field<16>()))
|
||||
{
|
||||
ThrowErrorIf(Error::ZipCentralDirectoryHeader, (Field<16>().value != 0xFFFFFFFF), "invalid zip64 local header offset");
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowErrorIf(Error::ZipCentralDirectoryHeader, (Field<16>().value >= pos.QuadPart), "invalid relative header offset");
|
||||
ThrowErrorIf(Error::ZipCentralDirectoryHeader, (Field<16>().get() >= pos.QuadPart), "invalid relative header offset");
|
||||
}
|
||||
|
||||
if (Field<17>().Size())
|
||||
{
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<17>().value.data()), static_cast<ULONG>(Field<17>().Size()), nullptr));
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<17>().get().data()), static_cast<ULONG>(Field<17>().Size()), nullptr));
|
||||
}
|
||||
|
||||
if (Field<18>().Size())
|
||||
{
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<18>().value.data()), static_cast<ULONG>(Field<18>().Size()), nullptr));
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<18>().get().data()), static_cast<ULONG>(Field<18>().Size()), nullptr));
|
||||
}
|
||||
// Only process for Zip64ExtendedInformation
|
||||
if (Field<18>().Size() > 2 && Field<18>().value[0] == 0x01 && Field<18>().value[1] == 0x00)
|
||||
if (Field<18>().Size() > 2 && Field<18>().get()[0] == 0x01 && Field<18>().get()[1] == 0x00)
|
||||
{
|
||||
LARGE_INTEGER zero = {0};
|
||||
ThrowHrIfFailed(stream->Seek(zero, StreamBase::Reference::CURRENT, &pos));
|
||||
auto vectorStream = ComPtr<IStream>::Make<VectorStream>(&Field<18>().value);
|
||||
ThrowErrorIfNot(Error::ZipCentralDirectoryHeader, (Field<18>().Size() >= m_extendedInfo.Size()), "Unexpected extended info size");
|
||||
m_extendedInfo.Read(vectorStream.Get(), pos);
|
||||
auto vectorStream = ComPtr<IStream>::Make<VectorStream>(&Field<18>());
|
||||
m_extendedInfo.Read(vectorStream.Get(), pos, Field<9>(), Field<8>(), Field<16>(), Field<13>());
|
||||
}
|
||||
|
||||
if (Field<19>().Size())
|
||||
{
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<19>().value.data()), static_cast<ULONG>(Field<19>().Size()), nullptr));
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<19>().get().data()), static_cast<ULONG>(Field<19>().Size()), nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,8 +249,8 @@ void CentralDirectoryFileHeader::Read(const ComPtr<IStream>& stream, bool isZip6
|
|||
LocalFileHeader::LocalFileHeader()
|
||||
{
|
||||
SetSignature(static_cast<std::uint32_t>(Signatures::LocalFileHeader));
|
||||
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension)); // always zip64
|
||||
SetGeneralPurposeBitFlags(static_cast<std::uint16_t>(GeneralPurposeBitFlags::GeneralPurposeBit));
|
||||
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension)); // deafult to zip64
|
||||
SetGeneralPurposeBitFlags(static_cast<std::uint16_t>(GeneralPurposeBitFlags::DataDescriptor));
|
||||
SetLastModFileTime(static_cast<std::uint16_t>(MagicNumbers::FileTime)); // TODO: figure out how to convert to msdos time
|
||||
SetLastModFileDate(static_cast<std::uint16_t>(MagicNumbers::FileDate));
|
||||
SetCrc(0);
|
||||
|
@ -249,7 +259,7 @@ LocalFileHeader::LocalFileHeader()
|
|||
SetExtraFieldLength(0);
|
||||
}
|
||||
|
||||
void LocalFileHeader::SetData(std::string& name, bool isCompressed)
|
||||
void LocalFileHeader::SetData(const std::string& name, bool isCompressed)
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
auto compressMethod = (isCompressed) ? CompressionType::Deflate : CompressionType::Store;
|
||||
|
@ -257,49 +267,59 @@ void LocalFileHeader::SetData(std::string& name, bool isCompressed)
|
|||
SetFileName(name);
|
||||
}
|
||||
|
||||
void LocalFileHeader::SetData(std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize)
|
||||
{
|
||||
THROW_IF_PACK_NOT_ENABLED
|
||||
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion));
|
||||
SetGeneralPurposeBitFlags(static_cast<std::uint16_t>(GetGeneralPurposeBitFlags() & ~GeneralPurposeBitFlags::DataDescriptor));
|
||||
SetCrc(crc);
|
||||
SetCompressedSize(static_cast<uint32_t>(compressedSize));
|
||||
SetUncompressedSize(static_cast<uint32_t>(uncompressedSize));
|
||||
}
|
||||
|
||||
void LocalFileHeader::Read(const ComPtr<IStream> &stream, CentralDirectoryFileHeader& directoryEntry)
|
||||
{
|
||||
StreamBase::Read(stream, &Field<0>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>( Field<0>().value, static_cast<std::uint32_t>(Signatures::LocalFileHeader));
|
||||
StreamBase::Read(stream, &Field<0>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>(), static_cast<std::uint32_t>(Signatures::LocalFileHeader));
|
||||
|
||||
StreamBase::Read(stream, &Field<1>().value);
|
||||
Meta::OnlyEitherValueValidation<std::uint16_t>(Field<1>().value, static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion),
|
||||
StreamBase::Read(stream, &Field<1>());
|
||||
Meta::OnlyEitherValueValidation<std::uint16_t>(Field<1>(), static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion),
|
||||
static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
|
||||
StreamBase::Read(stream, &Field<2>().value);
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, ((Field<2>().value & static_cast<std::uint16_t>(UnsupportedFlagsMask)) == 0), "unsupported flag(s) specified");
|
||||
StreamBase::Read(stream, &Field<2>());
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, ((Field<2>().get() & static_cast<std::uint16_t>(UnsupportedFlagsMask)) == 0), "unsupported flag(s) specified");
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, (IsGeneralPurposeBitSet() == directoryEntry.IsGeneralPurposeBitSet()), "inconsistent general purpose bits specified");
|
||||
|
||||
StreamBase::Read(stream, &Field<3>().value);
|
||||
Meta::OnlyEitherValueValidation<std::uint16_t>(Field<3>().value, static_cast<std::uint16_t>(CompressionType::Deflate),
|
||||
StreamBase::Read(stream, &Field<3>());
|
||||
Meta::OnlyEitherValueValidation<std::uint16_t>(Field<3>(), static_cast<std::uint16_t>(CompressionType::Deflate),
|
||||
static_cast<std::uint16_t>(CompressionType::Store));
|
||||
|
||||
StreamBase::Read(stream, &Field<4>().value);
|
||||
StreamBase::Read(stream, &Field<5>().value);
|
||||
StreamBase::Read(stream, &Field<6>().value);
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, (!IsGeneralPurposeBitSet() || (Field<6>().value == 0)), "Invalid Zip CRC");
|
||||
StreamBase::Read(stream, &Field<4>());
|
||||
StreamBase::Read(stream, &Field<5>());
|
||||
StreamBase::Read(stream, &Field<6>());
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, (!IsGeneralPurposeBitSet() || (Field<6>().get() == 0)), "Invalid Zip CRC");
|
||||
|
||||
StreamBase::Read(stream, &Field<7>().value);
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, (!IsGeneralPurposeBitSet() || (Field<7>().value == 0)), "Invalid Zip compressed size");
|
||||
StreamBase::Read(stream, &Field<7>());
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, (!IsGeneralPurposeBitSet() || (Field<7>().get() == 0)), "Invalid Zip compressed size");
|
||||
|
||||
StreamBase::Read(stream, &Field<8>().value);
|
||||
StreamBase::Read(stream, &Field<8>());
|
||||
|
||||
StreamBase::Read(stream, &Field<9>().value);
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, (Field<9>().value != 0), "unsupported file name size");
|
||||
Field<11>().value.resize(GetFileNameLength(), 0);
|
||||
StreamBase::Read(stream, &Field<9>());
|
||||
ThrowErrorIfNot(Error::ZipLocalFileHeader, (Field<9>().get() != 0), "unsupported file name size");
|
||||
Field<11>().get().resize(GetFileNameLength(), 0);
|
||||
|
||||
StreamBase::Read(stream, &Field<10>().value);
|
||||
StreamBase::Read(stream, &Field<10>());
|
||||
// Even if we don't validate them, we need to read the extra field
|
||||
if (Field<10>().value != 0) {Field<12>().value.resize(Field<10>().value, 0); }
|
||||
if (Field<10>().get() != 0) {Field<12>().get().resize(Field<10>().get(), 0); }
|
||||
|
||||
if (Field<11>().Size())
|
||||
{
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<11>().value.data()), static_cast<ULONG>(Field<11>().Size()), nullptr));
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<11>().get().data()), static_cast<ULONG>(Field<11>().Size()), nullptr));
|
||||
}
|
||||
|
||||
if (Field<12>().Size())
|
||||
{
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<12>().value.data()), static_cast<ULONG>(Field<12>().Size()), nullptr));
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<12>().get().data()), static_cast<ULONG>(Field<12>().Size()), nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,46 +346,46 @@ void Zip64EndOfCentralDirectoryRecord::SetData(std::uint64_t numCentralDirs, std
|
|||
|
||||
void Zip64EndOfCentralDirectoryRecord::Read(const ComPtr<IStream>& stream)
|
||||
{
|
||||
StreamBase::Read(stream, &Field<0>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>().value, static_cast<std::uint32_t>(Signatures::Zip64EndOfCD));
|
||||
StreamBase::Read(stream, &Field<0>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>(), static_cast<std::uint32_t>(Signatures::Zip64EndOfCD));
|
||||
|
||||
StreamBase::Read(stream, &Field<1>().value);
|
||||
StreamBase::Read(stream, &Field<1>());
|
||||
//4.3.14.1 The value stored into the "size of zip64 end of central
|
||||
// directory record" should be the size of the remaining
|
||||
// record and should not include the leading 12 bytes.
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, (Field<1>().value == (this->Size() - 12)), "invalid size of zip64 EOCD");
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, (Field<1>().get() == (this->Size() - 12)), "invalid size of zip64 EOCD");
|
||||
|
||||
StreamBase::Read(stream, &Field<2>().value);
|
||||
Meta::ExactValueValidation<std::uint16_t>(Field<2>().value, static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
StreamBase::Read(stream, &Field<2>());
|
||||
Meta::ExactValueValidation<std::uint16_t>(Field<2>(), static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
|
||||
StreamBase::Read(stream, &Field<3>().value);
|
||||
Meta::ExactValueValidation<std::uint16_t>(Field<3>().value, static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
StreamBase::Read(stream, &Field<3>());
|
||||
Meta::ExactValueValidation<std::uint16_t>(Field<3>(), static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
|
||||
|
||||
StreamBase::Read(stream, &Field<4>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<4>().value, 0);
|
||||
StreamBase::Read(stream, &Field<4>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<4>(), 0);
|
||||
|
||||
StreamBase::Read(stream, &Field<5>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<5>().value, 0);
|
||||
StreamBase::Read(stream, &Field<5>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<5>(), 0);
|
||||
|
||||
StreamBase::Read(stream, &Field<6>().value);
|
||||
Meta::NotValueValidation<std::uint64_t>(Field<6>().value, 0);
|
||||
StreamBase::Read(stream, &Field<6>());
|
||||
Meta::NotValueValidation<std::uint64_t>(Field<6>(), 0);
|
||||
|
||||
StreamBase::Read(stream, &Field<7>().value);
|
||||
Meta::NotValueValidation<std::uint64_t>(Field<7>().value, 0);
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, (Field<7>().value == GetTotalNumberOfEntries()), "invalid total number of entries");
|
||||
StreamBase::Read(stream, &Field<7>());
|
||||
Meta::NotValueValidation<std::uint64_t>(Field<7>(), 0);
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, (Field<7>().get() == GetTotalNumberOfEntries()), "invalid total number of entries");
|
||||
|
||||
ULARGE_INTEGER pos = {0};
|
||||
ThrowHrIfFailed(stream->Seek({0}, StreamBase::Reference::CURRENT, &pos));
|
||||
StreamBase::Read(stream, &Field<8>().value);
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, ((Field<8>().value != 0) && (Field<8>().value < pos.QuadPart)), "invalid size of central directory");
|
||||
StreamBase::Read(stream, &Field<8>());
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, ((Field<8>().get() != 0) && (Field<8>().get() < pos.QuadPart)), "invalid size of central directory");
|
||||
|
||||
ThrowHrIfFailed(stream->Seek({0}, StreamBase::Reference::CURRENT, &pos));
|
||||
StreamBase::Read(stream, &Field<9>().value);
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, ((Field<9>().value != 0) && (Field<9>().value < pos.QuadPart)), "invalid size of central directory");
|
||||
StreamBase::Read(stream, &Field<9>());
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, ((Field<9>().get() != 0) && (Field<9>().get() < pos.QuadPart)), "invalid size of central directory");
|
||||
|
||||
if (Field<10>().Size())
|
||||
{
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<10>().value.data()), static_cast<ULONG>(Field<10>().Size()), nullptr));
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<10>().get().data()), static_cast<ULONG>(Field<10>().Size()), nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,19 +406,19 @@ void Zip64EndOfCentralDirectoryLocator::SetData(std::uint64_t zip64EndCdrOffset)
|
|||
|
||||
void Zip64EndOfCentralDirectoryLocator::Read(const ComPtr<IStream>& stream)
|
||||
{
|
||||
StreamBase::Read(stream, &Field<0>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>().value, static_cast<std::uint32_t>(Signatures::Zip64EndOfCDLocator));
|
||||
StreamBase::Read(stream, &Field<0>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>(), static_cast<std::uint32_t>(Signatures::Zip64EndOfCDLocator));
|
||||
|
||||
StreamBase::Read(stream, &Field<1>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<1>().value, 0);
|
||||
StreamBase::Read(stream, &Field<1>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<1>(), 0);
|
||||
|
||||
ULARGE_INTEGER pos = {0};
|
||||
StreamBase::Read(stream, &Field<2>().value);
|
||||
StreamBase::Read(stream, &Field<2>());
|
||||
ThrowHrIfFailed(stream->Seek({0}, StreamBase::Reference::CURRENT, &pos));
|
||||
ThrowErrorIfNot(Error::Zip64EOCDLocator, ((Field<2>().value != 0) && (Field<2>().value < pos.QuadPart)), "Invalid relative offset");
|
||||
ThrowErrorIfNot(Error::Zip64EOCDLocator, ((Field<2>().get() != 0) && (Field<2>().get() < pos.QuadPart)), "Invalid relative offset");
|
||||
|
||||
StreamBase::Read(stream, &Field<3>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<3>().value, 1);
|
||||
StreamBase::Read(stream, &Field<3>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<3>(), 1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -408,8 +428,8 @@ EndCentralDirectoryRecord::EndCentralDirectoryRecord()
|
|||
{
|
||||
SetSignature(static_cast<std::uint32_t>(Signatures::EndOfCentralDirectory));
|
||||
// Always use zip64
|
||||
SetNumberOfDisk(std::numeric_limits<std::uint16_t>::max());
|
||||
SetDiskStart(std::numeric_limits<std::uint16_t>::max());
|
||||
SetNumberOfDisk(0);
|
||||
SetDiskStart(0);
|
||||
SetTotalNumberOfEntries(std::numeric_limits<std::uint16_t>::max());
|
||||
SetTotalEntriesInCentralDirectory(std::numeric_limits<std::uint16_t>::max());
|
||||
SetSizeOfCentralDirectory(std::numeric_limits<std::uint32_t>::max());
|
||||
|
@ -419,42 +439,45 @@ EndCentralDirectoryRecord::EndCentralDirectoryRecord()
|
|||
|
||||
void EndCentralDirectoryRecord::Read(const ComPtr<IStream>& stream)
|
||||
{
|
||||
StreamBase::Read(stream, &Field<0>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>().value, static_cast<std::uint32_t>(Signatures::EndOfCentralDirectory));
|
||||
StreamBase::Read(stream, &Field<0>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<0>(), static_cast<std::uint32_t>(Signatures::EndOfCentralDirectory));
|
||||
|
||||
StreamBase::Read(stream, &Field<1>().value);
|
||||
Meta::OnlyEitherValueValidation<std::uint32_t>(Field<1>().value, 0, 0xFFFF);
|
||||
StreamBase::Read(stream, &Field<1>());
|
||||
Meta::OnlyEitherValueValidation<std::uint32_t>(Field<1>(), 0, 0xFFFF);
|
||||
|
||||
StreamBase::Read(stream, &Field<2>().value);
|
||||
Meta::OnlyEitherValueValidation<std::uint32_t>(Field<2>().value, 0, 0xFFFF);
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, (Field<1>().value != Field<2>().value), "field missmatch");
|
||||
m_isZip64 = (0xFFFF == Field<2>().value);
|
||||
StreamBase::Read(stream, &Field<2>());
|
||||
Meta::OnlyEitherValueValidation<std::uint32_t>(Field<2>(), 0, 0xFFFF);
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, (Field<1>().get() != Field<2>().get()), "field missmatch");
|
||||
|
||||
StreamBase::Read(stream, &Field<3>().value);
|
||||
if (Field<3>().value != 0 && Field<3>().value != 0xFFFF)
|
||||
{ m_archiveHasZip64Locator = false;
|
||||
}
|
||||
StreamBase::Read(stream, &Field<3>());
|
||||
StreamBase::Read(stream, &Field<4>());
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, (Field<3>().get() != Field<4>().get()), "field missmatch");
|
||||
|
||||
StreamBase::Read(stream, &Field<4>().value);
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, (Field<3>().value != Field<4>().value), "field missmatch");
|
||||
StreamBase::Read(stream, &Field<5>());
|
||||
StreamBase::Read(stream, &Field<6>());
|
||||
|
||||
StreamBase::Read(stream, &Field<5>().value);
|
||||
StreamBase::Read(stream, &Field<6>().value);
|
||||
m_isZip64 = (
|
||||
IsValueInExtendedInfo(Field<1>()) ||
|
||||
IsValueInExtendedInfo(Field<2>()) ||
|
||||
IsValueInExtendedInfo(Field<3>()) ||
|
||||
IsValueInExtendedInfo(Field<4>()) ||
|
||||
IsValueInExtendedInfo(Field<5>()) ||
|
||||
IsValueInExtendedInfo(Field<6>()));
|
||||
|
||||
if(m_archiveHasZip64Locator)
|
||||
if (m_isZip64)
|
||||
{
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, ((Field<5>().value != 0) && (Field<5>().value != 0xFFFFFFFF)),
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, ((Field<5>().get() != 0) && (Field<5>().get() != 0xFFFFFFFF)),
|
||||
"unsupported size of central directory");
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, ((Field<6>().value != 0) && (Field<6>().value != 0xFFFFFFFF)),
|
||||
ThrowErrorIf(Error::ZipEOCDRecord, ((Field<6>().get() != 0) && (Field<6>().get() != 0xFFFFFFFF)),
|
||||
"unsupported offset of start of central directory");
|
||||
}
|
||||
|
||||
StreamBase::Read(stream, &Field<7>().value);
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<7>().value, 0);
|
||||
StreamBase::Read(stream, &Field<7>());
|
||||
Meta::ExactValueValidation<std::uint32_t>(Field<7>(), 0);
|
||||
|
||||
if (Field<8>().Size())
|
||||
{
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<8>().value.data()), static_cast<ULONG>(Field<8>().Size()), nullptr));
|
||||
ThrowHrIfFailed(stream->Read(reinterpret_cast<void*>(Field<8>().get().data()), static_cast<ULONG>(Field<8>().Size()), nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "MsixErrors.hpp"
|
||||
#include "Exceptions.hpp"
|
||||
#include "ContentType.hpp"
|
||||
#include "ZipFileStream.hpp"
|
||||
#include "Encoding.hpp"
|
||||
#include "ZipObjectWriter.hpp"
|
||||
#include "AppxManifestObject.hpp"
|
||||
|
@ -185,15 +184,15 @@ namespace MSIX {
|
|||
{
|
||||
opcFileName = name;
|
||||
}
|
||||
auto lfhSize = m_zipWriter->PrepareToAddFile(opcFileName, toCompress);
|
||||
auto fileInfo = m_zipWriter->PrepareToAddFile(opcFileName, toCompress);
|
||||
|
||||
// Add file to block map
|
||||
if (addToBlockMap)
|
||||
{
|
||||
m_blockMapWriter.AddFile(name, uncompressedSize, lfhSize);
|
||||
m_blockMapWriter.AddFile(name, uncompressedSize, fileInfo.first);
|
||||
}
|
||||
|
||||
auto zipFileStream = ComPtr<IStream>::Make<ZipFileStream>(opcFileName, toCompress);
|
||||
auto& zipFileStream = fileInfo.second;
|
||||
|
||||
std::uint64_t bytesToRead = uncompressedSize;
|
||||
std::uint32_t crc = 0;
|
||||
|
@ -238,8 +237,8 @@ namespace MSIX {
|
|||
}
|
||||
|
||||
// This could be the compressed or uncompressed size
|
||||
auto streamSize = zipFileStream.As<IStreamInternal>()->GetSize();
|
||||
m_zipWriter->AddFile(zipFileStream, crc, streamSize, uncompressedSize);
|
||||
auto streamSize = zipFileStream.As<IStreamInternal>()->GetSize();
|
||||
m_zipWriter->EndFile(crc, streamSize, uncompressedSize, true);
|
||||
}
|
||||
|
||||
bool AppxPackageWriter::IsFootPrintFile(std::string normalized)
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include "ZipObject.hpp"
|
||||
#include "MsixErrors.hpp"
|
||||
#include "Exceptions.hpp"
|
||||
#include "ZipFileStream.hpp"
|
||||
#include "DeflateStream.hpp"
|
||||
#include "StreamHelper.hpp"
|
||||
|
||||
namespace MSIX {
|
||||
|
||||
|
@ -22,10 +25,10 @@ namespace MSIX {
|
|||
public:
|
||||
DataDescriptor(std::uint32_t crc, std::uint64_t compressSize, std::uint64_t uncompressSize)
|
||||
{
|
||||
Field<0>().value = static_cast<std::uint32_t>(Signatures::DataDescriptor);
|
||||
Field<1>().value = crc;
|
||||
Field<2>().value = compressSize;
|
||||
Field<3>().value = uncompressSize;
|
||||
Field<0>() = static_cast<std::uint32_t>(Signatures::DataDescriptor);
|
||||
Field<1>() = crc;
|
||||
Field<2>() = compressSize;
|
||||
Field<3>() = uncompressSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -37,7 +40,7 @@ namespace MSIX {
|
|||
ZipObjectWriter::ZipObjectWriter(const ComPtr<IStorageObject>& storageObject) : ZipObject(storageObject)
|
||||
{
|
||||
// The storage object provided should had already initialize all the data.
|
||||
ThrowErrorIfNot(Error::Zip64EOCDLocator, m_endCentralDirectoryRecord.GetArchiveHasZip64Locator(),
|
||||
ThrowErrorIfNot(Error::Zip64EOCDRecord, m_endCentralDirectoryRecord.GetIsZip64(),
|
||||
"Editing non zip64 packages not supported");
|
||||
|
||||
// Move the stream at the start of central directory record so we can start overwritting.
|
||||
|
@ -61,38 +64,64 @@ namespace MSIX {
|
|||
}
|
||||
|
||||
// IZipWriter
|
||||
std::uint32_t ZipObjectWriter::PrepareToAddFile(std::string& name, bool isCompressed)
|
||||
std::pair<std::uint32_t, ComPtr<IStream>> ZipObjectWriter::PrepareToAddFile(const std::string& name, bool isCompressed)
|
||||
{
|
||||
ThrowErrorIf(Error::InvalidState, m_state != ZipObjectWriter::State::ReadyForLfhOrClose, "Invalid zip writer state");
|
||||
|
||||
// Get position were the lfh is going to be written
|
||||
ULARGE_INTEGER pos = {0};
|
||||
ThrowHrIfFailed(m_stream->Seek({0}, StreamBase::Reference::CURRENT, &pos));
|
||||
// write lfh
|
||||
|
||||
// Write lfh
|
||||
LocalFileHeader lfh;
|
||||
lfh.SetData(name, isCompressed);
|
||||
lfh.WriteTo(m_stream);
|
||||
|
||||
m_lastLFH = std::make_pair(static_cast<std::uint64_t>(pos.QuadPart), std::move(lfh));
|
||||
m_state = ZipObjectWriter::State::ReadyForFile;
|
||||
return static_cast<std::uint32_t>(m_lastLFH.second.Size());
|
||||
|
||||
ComPtr<IStream> zipStream = ComPtr<IStream>::Make<ZipFileStream>(name, isCompressed, m_stream.Get());
|
||||
if (isCompressed)
|
||||
{
|
||||
zipStream = ComPtr<IStream>::Make<DeflateStream>(zipStream);
|
||||
}
|
||||
|
||||
return std::make_pair(static_cast<std::uint32_t>(m_lastLFH.second.Size()), std::move(zipStream));
|
||||
}
|
||||
|
||||
void ZipObjectWriter::AddFile(MSIX::ComPtr<IStream>& fileStream, std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize)
|
||||
void ZipObjectWriter::EndFile(std::uint32_t crc, std::uint64_t compressedSize, std::uint64_t uncompressedSize, bool forceDataDescriptor)
|
||||
{
|
||||
ThrowErrorIf(Error::InvalidState, m_state != ZipObjectWriter::State::ReadyForFile, "Invalid zip writer state");
|
||||
// Write file stream
|
||||
LARGE_INTEGER start = { 0 };
|
||||
ThrowHrIfFailed(fileStream->Seek(start, StreamBase::Reference::START, nullptr));
|
||||
ULARGE_INTEGER bytesCount = { 0 };
|
||||
bytesCount.QuadPart = std::numeric_limits<std::uint64_t>::max();
|
||||
ThrowHrIfFailed(fileStream->CopyTo(m_stream.Get(), bytesCount, nullptr, nullptr));
|
||||
// Create and write data descriptor
|
||||
DataDescriptor descriptor = DataDescriptor(crc, compressedSize, uncompressedSize);
|
||||
descriptor.WriteTo(m_stream);
|
||||
|
||||
if (forceDataDescriptor ||
|
||||
compressedSize > MaxSizeToNotUseDataDescriptor ||
|
||||
uncompressedSize > MaxSizeToNotUseDataDescriptor)
|
||||
{
|
||||
// Create and write data descriptor
|
||||
DataDescriptor descriptor = DataDescriptor(crc, compressedSize, uncompressedSize);
|
||||
descriptor.WriteTo(m_stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The sizes can fit in the LFH, rewrite it with the new data
|
||||
Helper::StreamPositionReset resetAfterLFHWrite{ m_stream.Get() };
|
||||
|
||||
LARGE_INTEGER lfhLocation;
|
||||
lfhLocation.QuadPart = static_cast<LONGLONG>(m_lastLFH.first);
|
||||
ThrowHrIfFailed(m_stream->Seek(lfhLocation, StreamBase::Reference::START, nullptr));
|
||||
|
||||
// We cannot change the size of the LFH, ensure that we don't accidentally
|
||||
size_t currentSize = m_lastLFH.second.Size();
|
||||
m_lastLFH.second.SetData(crc, compressedSize, uncompressedSize);
|
||||
ThrowErrorIf(Error::Unexpected, currentSize != m_lastLFH.second.Size(), "Cannot change the LFH size when updating it");
|
||||
|
||||
m_lastLFH.second.WriteTo(m_stream);
|
||||
}
|
||||
|
||||
// Create and add cdh to map
|
||||
CentralDirectoryFileHeader cdh;
|
||||
auto name = m_lastLFH.second.GetFileName();
|
||||
cdh.SetData(name, crc, compressedSize, uncompressedSize, m_lastLFH.first, m_lastLFH.second.GetCompressionMethod());
|
||||
m_centralDirectories.insert(std::make_pair(name, std::move(cdh)));
|
||||
cdh.SetData(m_lastLFH.second.GetFileName(), crc, compressedSize, uncompressedSize, m_lastLFH.first, m_lastLFH.second.GetCompressionMethod(), forceDataDescriptor);
|
||||
m_centralDirectories.insert(std::make_pair(m_lastLFH.second.GetFileName(), std::move(cdh)));
|
||||
m_state = ZipObjectWriter::State::ReadyForLfhOrClose;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,21 +15,23 @@ namespace MSIX {
|
|||
ZipObjectReader::ZipObjectReader(const ComPtr<IStream>& stream) : ZipObject(stream)
|
||||
{
|
||||
LARGE_INTEGER pos = {0};
|
||||
pos.QuadPart = -1 * m_endCentralDirectoryRecord.Size();
|
||||
pos.QuadPart = m_endCentralDirectoryRecord.Size();
|
||||
pos.QuadPart *= -1;
|
||||
ThrowHrIfFailed(m_stream->Seek(pos, StreamBase::Reference::END, nullptr));
|
||||
m_endCentralDirectoryRecord.Read(m_stream.Get());
|
||||
|
||||
// find where the zip central directory exists.
|
||||
std::uint64_t offsetStartOfCD = 0;
|
||||
std::uint64_t totalNumberOfEntries = 0;
|
||||
if (!m_endCentralDirectoryRecord.GetArchiveHasZip64Locator())
|
||||
if (!m_endCentralDirectoryRecord.GetIsZip64())
|
||||
{
|
||||
offsetStartOfCD = m_endCentralDirectoryRecord.GetStartOfCentralDirectory();
|
||||
totalNumberOfEntries = m_endCentralDirectoryRecord.GetNumberOfCentralDirectoryEntries();
|
||||
}
|
||||
else
|
||||
{ // Make sure that we have a zip64 end of central directory locator
|
||||
pos.QuadPart = -1*(m_endCentralDirectoryRecord.Size() + m_zip64Locator.Size());
|
||||
pos.QuadPart = m_endCentralDirectoryRecord.Size() + m_zip64Locator.Size();
|
||||
pos.QuadPart *= -1;
|
||||
ThrowHrIfFailed(m_stream->Seek(pos, StreamBase::Reference::END, nullptr));
|
||||
m_zip64Locator.Read(m_stream.Get());
|
||||
|
||||
|
@ -52,7 +54,7 @@ namespace MSIX {
|
|||
m_centralDirectories.insert(std::make_pair(centralFileHeader.GetFileName(), std::move(centralFileHeader)));
|
||||
}
|
||||
|
||||
if (m_endCentralDirectoryRecord.GetArchiveHasZip64Locator())
|
||||
if (m_endCentralDirectoryRecord.GetIsZip64())
|
||||
{ // We should have no data between the end of the last central directory header and the start of the EoCD
|
||||
ULARGE_INTEGER uPos = {0};
|
||||
ThrowHrIfFailed(m_stream->Seek({0}, StreamBase::Reference::CURRENT, &uPos));
|
||||
|
@ -94,7 +96,7 @@ namespace MSIX {
|
|||
centralFileHeader->second.GetCompressionMethod() == CompressionType::Deflate,
|
||||
centralFileHeader->second.GetRelativeOffsetOfLocalHeader() + lfh.Size(),
|
||||
centralFileHeader->second.GetCompressedSize(),
|
||||
m_stream
|
||||
m_stream.Get()
|
||||
);
|
||||
|
||||
if (centralFileHeader->second.GetCompressionMethod() == CompressionType::Deflate)
|
||||
|
|
Загрузка…
Ссылка в новой задаче