Merged PR 945937: Merge psmith to feature

This commit is contained in:
Phil Smith 2017-10-04 21:33:57 +00:00
Родитель 0a54ba1b46
Коммит 56712c5d65
7 изменённых файлов: 682 добавлений и 564 удалений

Просмотреть файл

@ -19,9 +19,9 @@
7B5F64B61F7F824B009387FB /* StreamBase.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 7B5F64A61F7F824B009387FB /* StreamBase.hpp */; };
7B5F64B71F7F824B009387FB /* xPlatAppx.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 7B5F64A71F7F824B009387FB /* xPlatAppx.hpp */; };
7B5F64B81F7F824B009387FB /* ZipFileStream.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 7B5F64A81F7F824B009387FB /* ZipFileStream.hpp */; };
7B5F64B91F7F824B009387FB /* ZipStream.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 7B5F64A91F7F824B009387FB /* ZipStream.hpp */; };
7B5F64BA1F7F824B009387FB /* xPlatAppx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7B5F64AB1F7F824B009387FB /* xPlatAppx.cpp */; };
7B5F64BB1F7F824B009387FB /* ZipStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7B5F64AC1F7F824B009387FB /* ZipStream.cpp */; };
EE2E65D71F833E2D0070D4E4 /* ZipObject.hpp in Headers */ = {isa = PBXBuildFile; fileRef = EE2E65D61F833E2D0070D4E4 /* ZipObject.hpp */; };
EE2E65D91F833E460070D4E4 /* ZipObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE2E65D81F833E460070D4E4 /* ZipObject.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -38,9 +38,9 @@
7B5F64A61F7F824B009387FB /* StreamBase.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StreamBase.hpp; sourceTree = "<group>"; };
7B5F64A71F7F824B009387FB /* xPlatAppx.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = xPlatAppx.hpp; sourceTree = "<group>"; };
7B5F64A81F7F824B009387FB /* ZipFileStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ZipFileStream.hpp; sourceTree = "<group>"; };
7B5F64A91F7F824B009387FB /* ZipStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ZipStream.hpp; sourceTree = "<group>"; };
7B5F64AB1F7F824B009387FB /* xPlatAppx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xPlatAppx.cpp; sourceTree = "<group>"; };
7B5F64AC1F7F824B009387FB /* ZipStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ZipStream.cpp; sourceTree = "<group>"; };
EE2E65D61F833E2D0070D4E4 /* ZipObject.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ZipObject.hpp; sourceTree = "<group>"; };
EE2E65D81F833E460070D4E4 /* ZipObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ZipObject.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -82,6 +82,7 @@
7B5F649C1F7F824B009387FB /* inc */ = {
isa = PBXGroup;
children = (
EE2E65D61F833E2D0070D4E4 /* ZipObject.hpp */,
7B5F649D1F7F824B009387FB /* Base64Stream.hpp */,
7B5F649E1F7F824B009387FB /* CRC32Stream.hpp */,
7B5F649F1F7F824B009387FB /* Exceptions.hpp */,
@ -94,7 +95,6 @@
7B5F64A61F7F824B009387FB /* StreamBase.hpp */,
7B5F64A71F7F824B009387FB /* xPlatAppx.hpp */,
7B5F64A81F7F824B009387FB /* ZipFileStream.hpp */,
7B5F64A91F7F824B009387FB /* ZipStream.hpp */,
);
name = inc;
path = ../../src/inc;
@ -103,8 +103,8 @@
7B5F64AA1F7F824B009387FB /* xPlatAppx */ = {
isa = PBXGroup;
children = (
EE2E65D81F833E460070D4E4 /* ZipObject.cpp */,
7B5F64AB1F7F824B009387FB /* xPlatAppx.cpp */,
7B5F64AC1F7F824B009387FB /* ZipStream.cpp */,
);
name = xPlatAppx;
path = ../../src/xPlatAppx;
@ -120,8 +120,8 @@
7B5F64B51F7F824B009387FB /* SHA256Stream.hpp in Headers */,
7B5F64B01F7F824B009387FB /* FileStream.hpp in Headers */,
7B5F64AF1F7F824B009387FB /* Exceptions.hpp in Headers */,
EE2E65D71F833E2D0070D4E4 /* ZipObject.hpp in Headers */,
7B5F64B71F7F824B009387FB /* xPlatAppx.hpp in Headers */,
7B5F64B91F7F824B009387FB /* ZipStream.hpp in Headers */,
7B5F64AE1F7F824B009387FB /* CRC32Stream.hpp in Headers */,
7B5F64B21F7F824B009387FB /* OffsetStream.hpp in Headers */,
7B5F64B81F7F824B009387FB /* ZipFileStream.hpp in Headers */,
@ -190,8 +190,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EE2E65D91F833E460070D4E4 /* ZipObject.cpp in Sources */,
7B5F64BA1F7F824B009387FB /* xPlatAppx.cpp in Sources */,
7B5F64BB1F7F824B009387FB /* ZipStream.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -290,6 +290,7 @@
7B5F64961F7F807B009387FB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_PREFIX = lib;
@ -303,6 +304,7 @@
7B5F64971F7F807B009387FB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_PREFIX = lib;

Просмотреть файл

@ -4,144 +4,117 @@
#include <vector>
#include <functional>
#include <algorithm>
#include <tuple>
#include <type_traits>
#include <initializer_list>
#include "Exceptions.hpp"
#include "StreamBase.hpp"
namespace xPlat {
namespace Meta {
// A uniary type with Read, Write, Validate, and Size
class Object
// Represents a heterogeneous collection of types that can be operated on as a compile-time vector
template <typename... Types>
class TypeList
{
std::tuple<Types...> fields;
static constexpr std::size_t last_index{ std::tuple_size<std::tuple<Types...>>::value };
public:
Object(void* value) : v(value) {}
virtual ~Object() { }
template<std::size_t index = 0, typename FuncT>
inline typename std::enable_if<index == last_index, void>::type for_each(FuncT)
{ }
virtual void Write(StreamBase* stream) = 0;
virtual void Read(StreamBase* stream) = 0;
virtual void Validate() = 0;
virtual size_t Size() = 0;
template <class T>
static T* GetValue(Object* o)
template<std::size_t index = 0, typename FuncT>
inline typename std::enable_if<index < last_index, void>::type for_each(FuncT f)
{
return reinterpret_cast<T*>(o->v);
f(Field<index>());
for_each<index + 1, FuncT>(f);
}
template <class T>
static void SetValue(Object* o, T& value)
{
*reinterpret_cast<T*>(o->v) = value;
}
protected:
void* value() { return v; }
void* v = nullptr;
template <size_t index>
inline auto& Field() { return std::get<index>(fields); }
};
// Aggregates a collection of objects
// validation is handled incrementally via Read
// size is summation of size of all fields.
class StructuredObject : public Object
// Defines set of operations (size, write, read) for a serializable/deserializable type.
template <class... Types>
class StructuredObject : public TypeList<Types...>
{
public:
StructuredObject(std::initializer_list<std::shared_ptr<Object>> list) : Object(&fields), fields(list) { }
virtual void Write(StreamBase* stream) override
{
std::for_each(fields.begin(), fields.end(), [&](auto field) { field->Write(stream); });
}
virtual void Read(StreamBase* stream) override
{
std::for_each(fields.begin(), fields.end(), [&](auto field)
{
field->Read(stream);
field->Validate();
});
}
virtual void Validate() override {}
virtual size_t Size() override
size_t Size()
{
size_t result = 0;
std::for_each(fields.begin(), fields.end(), [&](auto field) { result += field->Size(); });
this->for_each([&](auto& item)
{
result += item.Size();
});
return result;
}
Object* Field(size_t index) { return fields[index].get(); }
void Write(StreamBase* stream)
{
offset = stream->Ftell();
this->for_each([&](auto& item)
{
item.Write(stream);
});
}
void Read(StreamBase* stream)
{
offset = stream->Ftell();
this->for_each([&](auto& item)
{
item.Read(stream);
});
}
virtual void Validate() { }
protected:
std::vector<std::shared_ptr<Object>> fields;
std::uint64_t offset = 0; // For debugging purposes!
};
// base type for serializable fields
// base type for individual serializable/deserializable fields
template <class T>
class FieldBase : public Object
class FieldBase
{
public:
using Lambda = std::function<void(T& v)>;
FieldBase(Lambda validator) : Object(&value), validate(validator) {}
virtual T& GetValue() { return value; }
virtual void SetValue(T& v) { value = v; }
virtual void Write(StreamBase* stream) override
FieldBase()
{
validation = [](T&){}; // empty validation by-default.
}
virtual void Write(StreamBase* stream)
{
offset = stream->Ftell();
StreamBase::Write<T>(stream, &value);
}
virtual void Read(StreamBase* stream) override
virtual void Read(StreamBase* stream)
{
offset = stream->Ftell();
StreamBase::Read<T>(stream, &value);
Validate();
}
void Validate() override { validate(GetValue()); }
virtual void Validate() { validation(this->value); }
virtual size_t Size() { return sizeof(T); }
virtual size_t Size() override { return sizeof(T); }
protected:
std::uint64_t offset = 0; // For debugging purposes!
T value;
Lambda validate;
T value;
Lambda validation;
};
// 2 byte field
class Field2Bytes : public FieldBase<std::uint16_t>
{
public:
Field2Bytes(Lambda&& validator) : FieldBase<std::uint16_t>(validator) {}
};
// 4 byte field
class Field4Bytes : public FieldBase<std::uint32_t>
{
public:
Field4Bytes(Lambda&& validator) : FieldBase<std::uint32_t>(validator) {}
};
// 8 byte field
class Field8Bytes : public FieldBase<std::uint64_t>
{
public:
Field8Bytes(Lambda&& validator) : FieldBase<std::uint64_t>(validator) {}
};
class Field2Bytes : public FieldBase<std::uint16_t> { };
class Field4Bytes : public FieldBase<std::uint32_t> { };
class Field8Bytes : public FieldBase<std::uint64_t> { };
// variable length field.
class FieldNBytes : public Object
class FieldNBytes : public FieldBase<std::vector<std::uint8_t>>
{
public:
using Lambda = std::function<void(std::vector<std::uint8_t>& v)>;
FieldNBytes(Lambda validator) : Object(&value), validate(validator) {}
size_t Size() override { return value.size(); }
virtual size_t Size() override { return value.size(); }
virtual void Validate() override { }
virtual void Write(StreamBase* stream) override
{
@ -153,12 +126,6 @@ namespace xPlat {
stream->Read(Size(), value.data());
Validate();
}
void Validate() override { validate(value); }
protected:
std::vector<std::uint8_t> value;
Lambda validate;
};
}
}
}

Просмотреть файл

@ -34,14 +34,14 @@ namespace xPlat {
template <class T>
static void Read(StreamBase* stream, T* value)
{
static_assert(std::is_pod<T>::value, "specified value type must be both trivial and standard-layout");
//static_assert(std::is_pod<T>::value, "specified value type must be both trivial and standard-layout");
stream->Read(sizeof(T), reinterpret_cast<std::uint8_t*>(const_cast<T*>(value)));
}
template <class T>
static void Write(StreamBase* stream, T* value)
{
static_assert(std::is_pod<T>::value, "specified value type must be both trivial and standard-layout");
//static_assert(std::is_pod<T>::value, "specified value type must be both trivial and standard-layout");
stream->Write(sizeof(T), reinterpret_cast<std::uint8_t*>(const_cast<T*>(value)));
}

Просмотреть файл

@ -11,11 +11,30 @@ namespace xPlat {
{
public:
// TODO: define what streams to pass in on the .ctor
ZipFileStream(std::string&& fileName) : fileName(std::move(fileName))
ZipFileStream(
std::string&& fileName,
std::uint32_t offset,
std::uint32_t compressedSize,
std::uint32_t uncompressedSize,
bool isCompressed
) :
m_fileName(std::move(fileName)),
m_offset(offset),
m_compressedSize(compressedSize),
m_uncompressedSize(uncompressedSize),
m_isCompressed(isCompressed)
{
}
protected:
std::string fileName;
std::string m_fileName;
// TODO: change to uint64_t when adding 4+GB support
std::uint32_t m_offset;
std::uint32_t m_compressedSize;
std::uint32_t m_uncompressedSize;
bool m_isCompressed = false;
std::uint64_t m_relativePosition = 0;
};
}

Просмотреть файл

@ -23,296 +23,34 @@ namespace xPlat {
InvalidZip64CentralDirectoryRecord = 5,
InvalidCentralDirectoryHeader = 6,
HiddenDataBetweenLastCDHandEoCD = 7,
InvalidLocalFileHeader = 8,
};
ZipException(std::string message, Error error) : ExceptionBase(ExceptionBase::Facility::ZIP), reason(message)
ZipException(std::string message, Error error) : reason(message), ExceptionBase(ExceptionBase::Facility::ZIP)
{
SetLastError(static_cast<std::uint32_t>(error));
}
std::string reason;
};
enum class ZipVersions : std::uint16_t
{
Zip32DefaultVersion = 20,
Zip64FormatExtension = 45,
};
// from ZIP file format specification detailed in AppNote.txt
enum class Signatures : std::uint32_t
{
LocalFileHeader = 0x04034b50,
DataDescriptor = 0x08074b50,
CentralFileHeader = 0x02014b50,
Zip64EndOfCD = 0x06064b50,
Zip64EndOfCDLocator = 0x07064b50,
EndOfCentralDirectory = 0x06054b50,
};
enum class CompressionType : std::uint16_t
{
Store = 0,
Deflate = 8,
};
// Hat tip to the people at Facebook. Timestamp for files in ZIP archive
// format held constant to make pack/unpack deterministic
enum class MagicNumbers : std::uint16_t
{
FileTime = 0x6B60, // kudos to those know this
FileDate = 0xA2B1, // :)
};
enum class GeneralPurposeBitFlags : std::uint16_t
{
UNSUPPORTED_0 = 0x0001, // Bit 0: If set, indicates that the file is encrypted.
Deflate_MaxCompress = 0x0002, // Maximum compression (-exx/-ex), otherwise, normal compression (-en)
Deflate_FastCompress = 0x0004, // Fast (-ef), if Max+Fast then SuperFast (-es) compression
CRC32_SizesZero = 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,
CompressedPatchedData = 0x0020,
UNSUPPORTED_6 = 0x0040, // Strong encryption.
UnUsed_7 = 0x0080, // currently unused
UnUsed_8 = 0x0100, // currently unused
UnUsed_9 = 0x0200, // currently unused
UnUsed_10 = 0x0400, // currently unused
EncodingMustUseUTF8 = 0x0800, // Language encoding flag (EFS). File name and comments fields MUST be encoded UTF-8
UNSUPPORTED_12 = 0x1000, // Reserved by PKWARE for enhanced compression
UNSUPPORTED_13 = 0x2000, // Set when encrypting the Central Directory
UNSUPPORTED_14 = 0x4000, // Reserved by PKWARE
UNSUPPORTED_15 = 0x8000, // Reserved by PKWARE
};
inline constexpr GeneralPurposeBitFlags operator &(GeneralPurposeBitFlags a, GeneralPurposeBitFlags b)
{ return static_cast<GeneralPurposeBitFlags>(static_cast<uint16_t>(a) & static_cast<uint16_t>(b));
}
inline constexpr GeneralPurposeBitFlags operator |(GeneralPurposeBitFlags a, GeneralPurposeBitFlags b)
{ return static_cast<GeneralPurposeBitFlags>(static_cast<uint16_t>(a) | static_cast<uint16_t>(b));
}
// if any of these are set, then fail.
constexpr static const GeneralPurposeBitFlags UnsupportedFlagsMask =
GeneralPurposeBitFlags::UNSUPPORTED_0 |
GeneralPurposeBitFlags::UNSUPPORTED_6 |
GeneralPurposeBitFlags::UNSUPPORTED_12 |
GeneralPurposeBitFlags::UNSUPPORTED_13 |
GeneralPurposeBitFlags::UNSUPPORTED_14 |
GeneralPurposeBitFlags::UNSUPPORTED_15;
class CentralDirectoryFileHeader : public Meta::StructuredObject
{
/* TODO: Implement large file support.
This type currently represents a "zip32" Central Directory Header. We need to refactor this into 3 types:
a "header" type that reads all the way down to field 7 (CRC-32) as-is, but that replaces fields 8 & 9 with a
new meta object type (ambiguous?) whose implementation is determined by the version needed to extract (field 2)'s
value.
This type would replace its existing compressed & uncompressed sizes properties (encapsulated in fields 8 & 9)
with a 64-bit value version of those methods:
std::uint64_t GetCompressedSize() { ...
std::uint64_t GetUncompressedSize() { ...
void SetCompressedSize (std::uint64_t...
void SetUncompressedSize(std::uint64_t...
The underlying implementation of these methods would validate the resulting in/out values and pass the correct
static_casted value to the new meta object type (ambiguous?) which would then hold the correct value, as well
as handle the correct sizes w.r.t. (de)serialization.
As-is I don't believe that we "need" this for now, so keeping the implementation "simpler" is probably the correct
answer for now.
*/
public:
virtual ~CentralDirectoryFileHeader() {}
CentralDirectoryFileHeader(StreamBase* s) : Meta::StructuredObject(
{
// 0 - central file header signature 4 bytes(0x02014b50)
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
{ if (v != static_cast<std::uint32_t>(Signatures::CentralFileHeader))
{ throw ZipException("signature mismatch", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
// 1 - version made by 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
{ if (v != static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension))
{ throw ZipException("unsupported version made by", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
// 2 - version needed to extract 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
{ if ((v != static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion)) &&
(v != static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension))
)
{ throw ZipException("unsupported version needed to extract", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
// 3 - general purpose bit flag 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
{ if ((v & static_cast<std::uint16_t>(UnsupportedFlagsMask)) != 0)
{ throw ZipException("unsupported flag(s) specified", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
// 4 - compression method 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
{ if ((v != static_cast<std::uint16_t>(CompressionType::Store)) &&
(v != static_cast<std::uint16_t>(CompressionType::Deflate))
)
{ throw ZipException("unsupported compression method", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
// 5 - last mod file time 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v) {}),
// 6 - last mod file date 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v) {}),
// 7 - crc - 32 4 bytes
std::make_shared<Meta::Field4Bytes>([&](std::uint32_t& v) {}),
// 8 - compressed size 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v) {}),
// 9 - uncompressed size 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v) {}),
//10 - file name length 2 bytes
std::make_shared<Meta::Field2Bytes>([&](std::uint16_t& v)
{ if (v > std::numeric_limits<std::uint16_t>::max())
{ throw ZipException("file name exceeds max size", ZipException::Error::InvalidCentralDirectoryHeader);
}
Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(17))->resize(v, 0);
}),
//11 - extra field length 2 bytes
std::make_shared<Meta::Field2Bytes>([&](std::uint16_t& v)
{ if (v > std::numeric_limits<std::uint16_t>::max())
{ throw ZipException("file name exceeds max size", ZipException::Error::InvalidCentralDirectoryHeader);
}
Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(18))->resize(v, 0);
}),
//12 - file comment length 2 bytes
std::make_shared<Meta::Field2Bytes>([&](std::uint16_t& v)
{ if (v > std::numeric_limits<std::uint16_t>::max())
{ throw ZipException("file comment exceeds max size", ZipException::Error::InvalidCentralDirectoryHeader);
}
Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(19))->resize(v, 0);
}),
//13 - disk number start 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported disk number start", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
//14 - internal file attributes 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported internal file attributes", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
//15 - external file attributes 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
{ if (v != 0)
{ //throw ZipException("unsupported external file attributes", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
//16 - relative offset of local header 4 bytes
std::make_shared<Meta::Field4Bytes>([&](std::uint32_t& v)
{ if (v >= m_stream->Ftell())
{ throw ZipException("invalid relative offset", ZipException::Error::InvalidCentralDirectoryHeader);
}
}),
//17 - file name(variable size)
std::make_shared<Meta::FieldNBytes>([](std::vector<std::uint8_t>& data) {}),
//18 - extra field(variable size)
std::make_shared<Meta::FieldNBytes>([](std::vector<std::uint8_t>& data) {}),
//19 - file comment(variable size)
std::make_shared<Meta::FieldNBytes>([](std::vector<std::uint8_t>& data) {})
}), m_stream(s)
{/*constructor*/
SetSignature(static_cast<std::uint32_t>(Signatures::CentralFileHeader));
SetVersionMadeBy(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
// only set to Zip64FormatExtension iff required!
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion));
SetLastModFileDate(static_cast<std::uint16_t>(MagicNumbers::FileDate));
SetLastModFileTime(static_cast<std::uint16_t>(MagicNumbers::FileTime));
SetExtraFieldLength(0);
SetFileCommentLength(0);
SetDiskNumberStart(0);
SetInternalFileAttributes(0);
SetExternalFileAttributes(0);
}
std::uint16_t GetVersionNeededToExtract() { return *Meta::Object::GetValue<std::uint16_t>(Field(2)); }
GeneralPurposeBitFlags GetGeneralPurposeBitFlag() { return static_cast<GeneralPurposeBitFlags>(*Meta::Object::GetValue<std::uint16_t>(Field(3))); }
void SetGeneralPurposeBitFlag(std::uint16_t value) { Meta::Object::SetValue(Field(3), value); }
std::uint16_t GetCompressionMethod() { return *Meta::Object::GetValue<std::uint16_t>(Field(4)); }
void SetCompressionMethod(std::uint16_t value) { Meta::Object::SetValue(Field(4), value); }
std::uint32_t GetCrc32() { return *Meta::Object::GetValue<std::uint32_t>(Field(7)); }
void SetCrc(std::uint32_t value) { Meta::Object::SetValue(Field(7), value); }
std::uint32_t GetCompressedSize() { return *Meta::Object::GetValue<std::uint32_t>(Field(8)); }
void SetCompressedSize(std::uint32_t value) { Meta::Object::SetValue(Field(8), value); }
std::uint32_t GetUncompressedSize() { return *Meta::Object::GetValue<std::uint32_t>(Field(9)); }
void SetUncompressedSize(std::uint32_t value) { Meta::Object::SetValue(Field(9), value); }
std::uint32_t GetRelativeOffsetOfLocalHeader() { return *Meta::Object::GetValue<std::uint32_t>(Field(16)); }
void SetRelativeOffsetOfLocalHeader(std::uint32_t value) { Meta::Object::SetValue(Field(16), value); }
std::string GetFileName()
{
auto data = Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(17));
return std::string(data->begin(), data->end());
}
void SetFileName(std::string name)
{
auto data = Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(17));
data->resize(name.size());
data->assign(name.begin(), name.end());
SetFileNameLength(static_cast<std::uint16_t>(name.size()));
}
private:
void SetSignature(std::uint32_t value) { Meta::Object::SetValue(Field(0), value); }
void SetVersionMadeBy(std::uint16_t value) { Meta::Object::SetValue(Field(1), value); }
void SetVersionNeededToExtract(std::uint16_t value) { Meta::Object::SetValue(Field(2), value); }
void SetLastModFileTime(std::uint16_t value) { Meta::Object::SetValue(Field(5), value); }
void SetLastModFileDate(std::uint16_t value) { Meta::Object::SetValue(Field(6), value); }
void SetFileNameLength(std::uint16_t value) { Meta::Object::SetValue(Field(10), value); }
void SetExtraFieldLength(std::uint16_t value) { Meta::Object::SetValue(Field(11), value); }
void SetFileCommentLength(std::uint16_t value) { Meta::Object::SetValue(Field(12), value); }
void SetDiskNumberStart(std::uint16_t value) { Meta::Object::SetValue(Field(13), value); }
void SetInternalFileAttributes(std::uint16_t value) { Meta::Object::SetValue(Field(14), value); }
void SetExternalFileAttributes(std::uint16_t value) { Meta::Object::SetValue(Field(15), value); }
StreamBase* m_stream = nullptr;
};//class CentralDirectoryFileHeader
// forward declarations
class CentralDirectoryFileHeader;
class LocalFileHeader;
// This represents a raw stream over a.zip file.
class ZipObject
{
public:
ZipObject(StreamPtr&& stream) : m_stream(std::move(stream)) { }
void Read();
ZipObject(StreamBase* stream);
std::vector<std::string> GetFileNames();
protected:
StreamPtr m_stream;
std::map<std::string, std::shared_ptr<ZipFileStream>> m_streams;
std::map<std::string, std::shared_ptr<CentralDirectoryFileHeader>> m_centralDirectory;
// TODO: change to uint64_t when adding full zip64 support
//std::map<std::uint32_t, std::shared_ptr<LocalFileHeader>> fileRepository;
std::map<std::uint32_t, std::shared_ptr<LocalFileHeader>> m_fileRepository;
};//class ZipObject
}
}

Просмотреть файл

@ -33,87 +33,83 @@ namespace xPlat {
[Zip64EndOfCentralDirectoryLocator]
[EndCentralDirectoryRecord]
*/
class LocalFileHeader : public Meta::StructuredObject
enum class ZipVersions : std::uint16_t
{
public:
std::uint16_t GetFileNameLength() { return *Meta::Object::GetValue<std::uint16_t>(Field(9)); }
void SetFileNameLength(std::uint16_t value) { Meta::Object::SetValue(Field(9), value); }
std::uint16_t GetExtraFieldLength() { return *Meta::Object::GetValue<std::uint16_t>(Field(10)); }
void SetExtraFieldLength(std::uint16_t value) { Meta::Object::SetValue(Field(10), value); }
std::uint32_t GetCompressedSize() { return *Meta::Object::GetValue<std::uint32_t>(Field(7)); }
void SetCompressedSize(std::uint32_t value) { Meta::Object::SetValue(Field(7), value); }
std::uint32_t GetUncompressedSize() { return *Meta::Object::GetValue<std::uint32_t>(Field(8)); }
void SetUncompressedSize(std::uint32_t value) { Meta::Object::SetValue(Field(8), value); }
Zip32DefaultVersion = 20,
Zip64FormatExtension = 45,
};
std::string GetFileName() {
auto data = *Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(11));
return std::string(data.begin(), data.end());
}
// from ZIP file format specification detailed in AppNote.txt
enum class Signatures : std::uint32_t
{
LocalFileHeader = 0x04034b50,
DataDescriptor = 0x08074b50,
CentralFileHeader = 0x02014b50,
Zip64EndOfCD = 0x06064b50,
Zip64EndOfCDLocator = 0x07064b50,
EndOfCentralDirectory = 0x06054b50,
};
void SetFileName(std::string name)
{
auto data = *Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(11));
data.resize(name.size());
data.assign(name.begin(), name.end());
SetFileNameLength(static_cast<std::uint16_t>(name.size()));
}
enum class CompressionType : std::uint16_t
{
Store = 0,
Deflate = 8,
};
LocalFileHeader() : Meta::StructuredObject(
{
// 0 - local file header signature 4 bytes(0x04034b50)
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
{
if (v != static_cast<std::uint32_t>(Signatures::LocalFileHeader))
{
throw ZipException("file header does not match signature", ZipException::Error::InvalidHeader);
}
}),
// 1 - version needed to extract 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v) {}),
// 2 - general purpose bit flag 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v) {}),
// 3 - compression method 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v) {}),
// 4 - last mod file time 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v) {}),
// 5 - last mod file date 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v) {}),
// 6 - crc - 32 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v) {}),
// 7 - compressed size 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v) {}),
// 8 - uncompressed size 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v) {}),
// 9 - file name length 2 bytes
std::make_shared<Meta::Field2Bytes>([&](std::uint16_t& v)
{
if (GetFileNameLength() > std::numeric_limits<std::uint16_t>::max())
{
throw ZipException("file name field exceeds max size", ZipException::Error::FieldOutOfRange);
}
Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(11))->resize(GetFileNameLength(), 0);
}),
// 10- extra field length 2 bytes
std::make_shared<Meta::Field2Bytes>([&](std::uint16_t& v)
{
if (GetExtraFieldLength() > std::numeric_limits<std::uint16_t>::max())
{
throw ZipException("extra field exceeds max size", ZipException::Error::FieldOutOfRange);
}
Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(12))->resize(GetExtraFieldLength(), 0);
}),
// 11- file name (variable size)
std::make_shared<Meta::FieldNBytes>([](std::vector<std::uint8_t>& data) {}),
// 12- extra field (variable size)
std::make_shared<Meta::FieldNBytes>([](std::vector<std::uint8_t>& data) {})
})
{/*constructor*/
}
}; //class LocalFileHeader
// Hat tip to the people at Facebook. Timestamp for files in ZIP archive
// format held constant to make pack/unpack deterministic
enum class MagicNumbers : std::uint16_t
{
FileTime = 0x6B60, // kudos to those know this
FileDate = 0xA2B1, // :)
};
enum class GeneralPurposeBitFlags : std::uint16_t
{
UNSUPPORTED_0 = 0x0001, // Bit 0: If set, indicates that the file is encrypted.
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
// the correct values are put in the data descriptor immediately following the
// compressed data.
EnhancedDeflate = 0x0010,
CompressedPatchedData = 0x0020,
UNSUPPORTED_6 = 0x0040, // Strong encryption.
UnUsed_7 = 0x0080, // currently unused
UnUsed_8 = 0x0100, // currently unused
UnUsed_9 = 0x0200, // currently unused
UnUsed_10 = 0x0400, // currently unused
EncodingMustUseUTF8 = 0x0800, // Language encoding flag (EFS). File name and comments fields MUST be encoded UTF-8
UNSUPPORTED_12 = 0x1000, // Reserved by PKWARE for enhanced compression
UNSUPPORTED_13 = 0x2000, // Set when encrypting the Central Directory
UNSUPPORTED_14 = 0x4000, // Reserved by PKWARE
UNSUPPORTED_15 = 0x8000, // Reserved by PKWARE
};
inline constexpr GeneralPurposeBitFlags operator &(GeneralPurposeBitFlags a, GeneralPurposeBitFlags b)
{
return static_cast<GeneralPurposeBitFlags>(static_cast<uint16_t>(a) & static_cast<uint16_t>(b));
}
inline constexpr GeneralPurposeBitFlags operator |(GeneralPurposeBitFlags a, GeneralPurposeBitFlags b)
{
return static_cast<GeneralPurposeBitFlags>(static_cast<uint16_t>(a) | static_cast<uint16_t>(b));
}
// if any of these are set, then fail.
constexpr static const GeneralPurposeBitFlags UnsupportedFlagsMask =
GeneralPurposeBitFlags::UNSUPPORTED_0 |
GeneralPurposeBitFlags::UNSUPPORTED_6 |
GeneralPurposeBitFlags::UNSUPPORTED_12 |
GeneralPurposeBitFlags::UNSUPPORTED_13 |
GeneralPurposeBitFlags::UNSUPPORTED_14 |
GeneralPurposeBitFlags::UNSUPPORTED_15;
/*
class DataDescriptor : public Meta::StructuredObject
{
public:
@ -136,23 +132,377 @@ namespace xPlat {
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v) {})
})
{/*constructor*/
{
}
};//class DataDescriptor
*/
class Zip64EndOfCentralDirectoryRecord : public Meta::StructuredObject
/* TODO: Implement large file support.
This type currently represents a "zip32" Central Directory Header. We need to create a new field type (offset)
to replace the type for fields 8 & 9 whose implementation is determined by the version needed to extract (field 2)'s
value.
This type would replace its existing compressed & uncompressed sizes properties (encapsulated in fields 8 & 9)
with a 64-bit value version of those methods:
std::uint64_t GetCompressedSize() { ...
std::uint64_t GetUncompressedSize() { ...
void SetCompressedSize (std::uint64_t...
void SetUncompressedSize(std::uint64_t...
The underlying implementation of these methods would validate the resulting in/out values and pass the correct
static_casted value to the new meta object type (offset) which would then hold the correct value, as well
as handle the correct sizes w.r.t. (de)serialization.
As-is I don't believe that we "need" this for now, so keeping the implementation "simpler" is probably the correct
answer for now.
*/
class CentralDirectoryFileHeader : public Meta::StructuredObject<
Meta::Field4Bytes, // 0 - central file header signature 4 bytes(0x02014b50)
Meta::Field2Bytes, // 1 - version made by 2 bytes
Meta::Field2Bytes, // 2 - version needed to extract 2 bytes
Meta::Field2Bytes, // 3 - general purpose bit flag 2 bytes
Meta::Field2Bytes, // 4 - compression method 2 bytes
Meta::Field2Bytes, // 5 - last mod file time 2 bytes
Meta::Field2Bytes, // 6 - last mod file date 2 bytes
Meta::Field4Bytes, // 7 - crc - 32 4 bytes
Meta::Field4Bytes, // 8 - compressed size 4 bytes
Meta::Field4Bytes, // 9 - uncompressed size 4 bytes
Meta::Field2Bytes, //10 - file name length 2 bytes
Meta::Field2Bytes, //11 - extra field length 2 bytes
Meta::Field2Bytes, //12 - file comment length 2 bytes
Meta::Field2Bytes, //13 - disk number start 2 bytes
Meta::Field2Bytes, //14 - internal file attributes 2 bytes
Meta::Field4Bytes, //15 - external file attributes 4 bytes
Meta::Field4Bytes, //16 - relative offset of local header 4 bytes
Meta::FieldNBytes, //17 - file name(variable size)
Meta::FieldNBytes, //18 - extra field(variable size)
Meta::FieldNBytes //19 - file comment(variable size)
>
{
public:
Zip64EndOfCentralDirectoryRecord(StreamBase* s) : Meta::StructuredObject(
CentralDirectoryFileHeader(StreamBase* s) : m_stream(s)
{
// 0 - central file header signature 4 bytes(0x02014b50)
Field<0>().validation = [](std::uint32_t& v)
{ if (v != static_cast<std::uint32_t>(Signatures::CentralFileHeader))
{ throw ZipException("signature mismatch", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
// 1 - version made by 2 bytes
Field<1>().validation = [](std::uint16_t& v)
{ if (v != static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension))
{ throw ZipException("unsupported version made by", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
// 2 - version needed to extract 2 bytes
Field<2>().validation = [](std::uint16_t& v)
{ if ((v != static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion)) &&
(v != static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension))
)
{ throw ZipException("unsupported version needed to extract", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
// 3 - general purpose bit flag 2 bytes
Field<3>().validation = [](std::uint16_t& v)
{ if ((v & static_cast<std::uint16_t>(UnsupportedFlagsMask)) != 0)
{ throw ZipException("unsupported flag(s) specified", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
// 4 - compression method 2 bytes
Field<4>().validation = [](std::uint16_t& v)
{ if ((v != static_cast<std::uint16_t>(CompressionType::Store)) &&
(v != static_cast<std::uint16_t>(CompressionType::Deflate))
)
{ throw ZipException("unsupported compression method", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
// 5 - last mod file time 2 bytes
// 6 - last mod file date 2 bytes
// 7 - crc - 32 4 bytes
// 8 - compressed size 4 bytes
// 9 - uncompressed size 4 bytes
//10 - file name length 2 bytes
Field<10>().validation = [&](std::uint16_t& v)
{ if (v == 0)
{ throw ZipException("unsupported file name size", ZipException::Error::InvalidCentralDirectoryHeader);
}
Field<17>().value.resize(v,0);
};
//11 - extra field length 2 bytes
Field<11>().validation = [&](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported extra field size", ZipException::Error::InvalidCentralDirectoryHeader);
}
Field<18>().value.resize(v,0);
};
//12 - file comment length 2 bytes
Field<12>().validation = [&](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported file comment size", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
//13 - disk number start 2 bytes
Field<13>().validation = [](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported disk number start", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
//14 - internal file attributes 2 bytes
Field<14>().validation = [](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported internal file attributes", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
//15 - external file attributes 4 bytes
//16 - relative offset of local header 4 bytes
Field<16>().validation = [&](std::uint32_t& v)
{ if (v >= m_stream->Ftell())
{ throw ZipException("invalid relative offset", ZipException::Error::InvalidCentralDirectoryHeader);
}
};
//17 - file name(variable size)
//18 - extra field(variable size)
//19 - file comment(variable size)
SetSignature(static_cast<std::uint32_t>(Signatures::CentralFileHeader));
SetVersionMadeBy(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
// only set to Zip64FormatExtension iff required!
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion));
SetLastModFileDate(static_cast<std::uint16_t>(MagicNumbers::FileDate));
SetLastModFileTime(static_cast<std::uint16_t>(MagicNumbers::FileTime));
SetExtraFieldLength(0);
SetFileCommentLength(0);
SetDiskNumberStart(0);
SetInternalFileAttributes(0);
SetExternalFileAttributes(0);
}
bool IsGeneralPurposeBitSet()
{
return ((GetGeneralPurposeBitFlags() & GeneralPurposeBitFlags::GeneralPurposeBit) == GeneralPurposeBitFlags::GeneralPurposeBit);
}
std::uint16_t GetVersionNeededToExtract() { return Field<2>().value; }
GeneralPurposeBitFlags GetGeneralPurposeBitFlags() { return static_cast<GeneralPurposeBitFlags>(Field<3>().value); }
void SetGeneralPurposeBitFlags(std::uint16_t value) { Field<3>().value = value; }
std::uint16_t GetCompressionMethod() { return Field<4>().value; }
void SetCompressionMethod(std::uint16_t value) { Field<4>().value= value; }
std::uint32_t GetCrc32() { return Field<7>().value; }
void SetCrc(std::uint32_t value) { Field<7>().value = value; }
std::uint32_t GetCompressedSize() { return Field<8>().value; }
void SetCompressedSize(std::uint32_t value) { Field<8>().value = value; }
std::uint32_t GetUncompressedSize() { return Field<9>().value; }
void SetUncompressedSize(std::uint32_t value) { Field<9>().value = value; }
std::uint32_t GetRelativeOffsetOfLocalHeader() { return Field<16>().value; }
void SetRelativeOffsetOfLocalHeader(std::uint32_t value) { Field<16>().value = value; }
std::string GetFileName()
{
auto data = Field<17>().value;
return std::string(data.begin(), data.end());
}
void SetFileName(std::string name)
{
auto data = Field<17>().value;
data.resize(name.size());
data.assign(name.begin(), name.end());
SetFileNameLength(static_cast<std::uint16_t>(name.size()));
}
private:
void SetSignature(std::uint32_t value) { Field<0>().value = value; }
void SetVersionMadeBy(std::uint16_t value) { Field<1>().value = value; }
void SetVersionNeededToExtract(std::uint16_t value) { Field<2>().value = value; }
void SetLastModFileTime(std::uint16_t value) { Field<5>().value = value; }
void SetLastModFileDate(std::uint16_t value) { Field<6>().value = value; }
void SetFileNameLength(std::uint16_t value) { Field<10>().value = value; }
void SetExtraFieldLength(std::uint16_t value) { Field<11>().value = value; }
void SetFileCommentLength(std::uint16_t value) { Field<12>().value = value; }
void SetDiskNumberStart(std::uint16_t value) { Field<13>().value = value; }
void SetInternalFileAttributes(std::uint16_t value) { Field<14>().value = value; }
void SetExternalFileAttributes(std::uint16_t value) { Field<15>().value = value; }
StreamBase* m_stream = nullptr;
};//class CentralDirectoryFileHeader
class LocalFileHeader : public Meta::StructuredObject<
Meta::Field4Bytes, // 0 - local file header signature 4 bytes(0x04034b50)
Meta::Field2Bytes, // 1 - version needed to extract 2 bytes
Meta::Field2Bytes, // 2 - general purpose bit flag 2 bytes
Meta::Field2Bytes, // 3 - compression method 2 bytes
Meta::Field2Bytes, // 4 - last mod file time 2 bytes
Meta::Field2Bytes, // 5 - last mod file date 2 bytes
Meta::Field4Bytes, // 6 - crc - 32 4 bytes
Meta::Field4Bytes, // 7 - compressed size 4 bytes
Meta::Field4Bytes, // 8 - uncompressed size 4 bytes
Meta::Field2Bytes, // 9 - file name length 2 bytes
Meta::Field2Bytes, // 10- extra field length 2 bytes
Meta::FieldNBytes, // 11- file name (variable size)
Meta::FieldNBytes // 12- extra field (variable size)
>
{
public:
LocalFileHeader(std::shared_ptr<CentralDirectoryFileHeader> directoryEntry) : m_directoryEntry(directoryEntry)
{
// 0 - local file header signature 4 bytes(0x04034b50)
Field<0>().validation = [](std::uint32_t& v)
{ if (v != static_cast<std::uint32_t>(Signatures::LocalFileHeader))
{ throw ZipException("file header does not match signature", ZipException::Error::InvalidLocalFileHeader);
}
};
// 1 - version needed to extract 2 bytes
Field<1>().validation = [](std::uint16_t& v)
{ if ((v != static_cast<std::uint16_t>(ZipVersions::Zip32DefaultVersion)) &&
(v != static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension))
)
{ throw ZipException("unsupported version needed to extract", ZipException::Error::InvalidLocalFileHeader);
}
};
// 2 - general purpose bit flag 2 bytes
Field<2>().validation = [&](std::uint16_t& v)
{ if ((v & static_cast<std::uint16_t>(UnsupportedFlagsMask)) != 0)
{ throw ZipException("unsupported flag(s) specified", ZipException::Error::InvalidLocalFileHeader);
}
if (IsGeneralPurposeBitSet() != m_directoryEntry->IsGeneralPurposeBitSet())
{ throw ZipException("inconsistent general purpose bits specified", ZipException::Error::InvalidLocalFileHeader);
}
};
// 3 - compression method 2 bytes
Field<3>().validation = [](std::uint16_t& v)
{ if ((v != static_cast<std::uint16_t>(CompressionType::Store)) &&
(v != static_cast<std::uint16_t>(CompressionType::Deflate))
)
{ throw ZipException("unsupported compression method", ZipException::Error::InvalidLocalFileHeader);
}
};
// 4 - last mod file time 2 bytes
// 5 - last mod file date 2 bytes
// 6 - crc - 32 4 bytes
Field<6>().validation = [&](std::uint32_t& v)
{ if (IsGeneralPurposeBitSet() && (v != 0))
{ throw ZipException("Invalid CRC", ZipException::Error::InvalidLocalFileHeader);
}
};
// 7 - compressed size 4 bytes
Field<7>().validation = [&](std::uint32_t& v)
{ if (IsGeneralPurposeBitSet() && (v != 0))
{ throw ZipException("Invalid compressed size", ZipException::Error::InvalidLocalFileHeader);
}
};
// 8 - uncompressed size 4 bytes
Field<8>().validation = [&](std::uint32_t& v)
{ if (IsGeneralPurposeBitSet() && (v != 0))
{ throw ZipException("Invalid uncompressed size", ZipException::Error::InvalidLocalFileHeader);
}
};
// 9 - file name length 2 bytes
Field<9>().validation = [&](std::uint16_t& v)
{ if (v == 0)
{ throw ZipException("unsupported file name size", ZipException::Error::InvalidLocalFileHeader);
}
Field<11>().value.resize(GetFileNameLength(), 0);
};
// 10- extra field length 2 bytes
Field<10>().validation = [&](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported extra field size", ZipException::Error::InvalidLocalFileHeader);
}
Field<12>().value.resize(GetExtraFieldLength(), 0);
};
// 11- file name (variable size)
// 12- extra field (variable size)
}
bool IsGeneralPurposeBitSet()
{
return ((GetGeneralPurposeBitFlags() & GeneralPurposeBitFlags::GeneralPurposeBit) == GeneralPurposeBitFlags::GeneralPurposeBit);
}
GeneralPurposeBitFlags GetGeneralPurposeBitFlags() { return static_cast<GeneralPurposeBitFlags>(Field<2>().value); }
CompressionType GetCompressionType() { return static_cast<CompressionType>(Field<3>().value); }
std::uint32_t GetCompressedSize()
{
if (IsGeneralPurposeBitSet())
{
return m_directoryEntry->GetCompressedSize();
}
return Field<7>().value;
}
std::uint32_t GetUncompressedSize()
{
if (IsGeneralPurposeBitSet())
{
return m_directoryEntry->GetUncompressedSize();
}
return Field<8>().value;
}
std::uint16_t GetFileNameLength() { return Field<9>().value; }
std::uint16_t GetExtraFieldLength() { return Field<10>().value; }
void SetGeneralPurposeBitFlag(std::uint16_t value) { Field<2>().value = value; }
void SetCompressedSize(std::uint32_t value) { Field<7>().value = value; }
void SetUncompressedSize(std::uint32_t value) { Field<8>().value = value; }
void SetFileNameLength(std::uint16_t value) { Field<9>().value = value; }
void SetExtraFieldLength(std::uint16_t value) { Field<10>().value = value; }
std::string GetFileName()
{
auto data = Field<11>().value;
return std::string(data.begin(), data.end());
}
void SetFileName(std::string name)
{
auto data = Field<11>().value;
data.resize(name.size());
data.assign(name.begin(), name.end());
SetFileNameLength(static_cast<std::uint16_t>(name.size()));
}
protected:
std::shared_ptr<CentralDirectoryFileHeader> m_directoryEntry = nullptr;
}; //class LocalFileHeader
class Zip64EndOfCentralDirectoryRecord : public Meta::StructuredObject<
Meta::Field4Bytes, // 0 - zip64 end of central dir signature 4 bytes(0x06064b50)
Meta::Field8Bytes, // 1 - size of zip64 end of central directory record 8 bytes
Meta::Field2Bytes, // 2 - version made by 2 bytes
Meta::Field2Bytes, // 3 - version needed to extract 2 bytes
Meta::Field4Bytes, // 4 - number of this disk 4 bytes
Meta::Field4Bytes, // 5 - number of the disk with the start of the central directory 4 bytes
Meta::Field8Bytes, // 6 - total number of entries in the central directory on this disk 8 bytes
Meta::Field8Bytes, // 7 - total number of entries in the central directory 8 bytes
Meta::Field8Bytes, // 8 - size of the central directory 8 bytes
Meta::Field8Bytes, // 9 - offset of start of central directory with respect to the
// starting disk number 8 bytes
Meta::FieldNBytes //10 - zip64 extensible data sector (variable size)
>
{
public:
Zip64EndOfCentralDirectoryRecord(StreamBase* s) : m_stream(s)
{
// 0 - zip64 end of central dir signature 4 bytes(0x06064b50)
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<0>().validation = [](std::uint32_t& v)
{ if (v != static_cast<std::uint32_t>(Signatures::Zip64EndOfCD))
{ throw ZipException("end of zip64 central directory does not match signature", ZipException::Error::InvalidHeader);
}
}),
};
// 1 - size of zip64 end of central directory record 8 bytes
std::make_shared<Meta::Field8Bytes>([&](std::uint64_t& v)
Field<1>().validation = [&](std::uint64_t& v)
{ //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.
@ -160,211 +510,226 @@ namespace xPlat {
if (v != size)
{ throw ZipException("invalid size of zip64 EOCD", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 2 - version made by 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
Field<2>().validation = [](std::uint16_t& v)
{ if (v != static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension))
{ throw ZipException("invalid zip64 EOCD version made by", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 3 - version needed to extract 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
Field<3>().validation = [](std::uint16_t& v)
{ if (v != static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension))
{ throw ZipException("invalid zip64 EOCD version to extract", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 4 - number of this disk 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<4>().validation = [](std::uint32_t& v)
{ if (v != 0)
{ throw ZipException("invalid disk number", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 5 - number of the disk with the start of the central directory 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<5>().validation = [](std::uint32_t& v)
{ if (v != 0)
{ throw ZipException("invalid disk index", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 6 - total number of entries in the central directory on this disk 8 bytes
std::make_shared<Meta::Field8Bytes>([](std::uint64_t& v)
Field<6>().validation = [](std::uint64_t& v)
{ if (v == 0)
{ throw ZipException("invalid number of entries", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 7 - total number of entries in the central directory 8 bytes
std::make_shared<Meta::Field8Bytes>([&](std::uint64_t& v)
Field<7>().validation = [&](std::uint64_t& v)
{ if (v != this->GetTotalNumberOfEntries())
{ throw ZipException("invalid total number of entries", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 8 - size of the central directory 8 bytes
std::make_shared<Meta::Field8Bytes>([&](std::uint64_t& v)
Field<8>().validation = [&](std::uint64_t& v)
{ // TODO: tighten up this validation
if ((v == 0) ||
(v >= m_stream->Ftell()))
{ throw ZipException("invalid size of central directory", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
// 9 - offset of start of central directory with respect to the starting disk number 8 bytes
std::make_shared<Meta::Field8Bytes>([&](std::uint64_t& v)
Field<9>().validation = [&](std::uint64_t& v)
{ // TODO: tighten up this validation
if ((v == 0) ||
(v >= m_stream->Ftell()))
{ throw ZipException("invalid start of central directory", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
}),
};
//10 - zip64 extensible data sector(variable size)
std::make_shared<Meta::FieldNBytes>([](std::vector<std::uint8_t>& data)
Field<10>().validation = [](std::vector<std::uint8_t>& data)
{ if (data.size() != 0)
{ throw ZipException("unsupported extensible data", ZipException::Error::InvalidZip64CentralDirectoryRecord);
}
})
}), m_stream(s)
{
};
SetSignature(static_cast<std::uint32_t>(Signatures::Zip64EndOfCD));
SetGetSizeOfZip64CDRecord(this->Size() - 12);
SetVersionMadeBy(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
SetVersionNeededToExtract(static_cast<std::uint16_t>(ZipVersions::Zip64FormatExtension));
SetNumberOfThisDisk(0);
SetTotalNumberOfEntries(0);
Meta::Object::GetValue<std::vector<std::uint8_t>>(Field(10))->resize(0);
}/*constructor*/
std::uint64_t GetTotalNumberOfEntries()
{
return *Meta::Object::GetValue<std::uint64_t>(Field(6));
Field<10>().value.resize(0);
}
std::uint64_t GetTotalNumberOfEntries() { return Field<6>().value; }
void SetTotalNumberOfEntries(std::uint64_t value)
{
Meta::Object::SetValue(Field(6), value);
Meta::Object::SetValue(Field(7), value);
Field<6>().value = value;
Field<7>().value = value;
}
std::uint64_t GetSizeOfCD() { return *Meta::Object::GetValue<std::uint64_t>(Field(8)); }
void SetSizeOfCD(std::uint64_t value) { Meta::Object::SetValue(Field(8), value); }
std::uint64_t GetOffsetfStartOfCD() { return *Meta::Object::GetValue<std::uint64_t>(Field(9)); }
void SetOffsetfStartOfCD(std::uint64_t value) { Meta::Object::SetValue(Field(9), value); }
std::uint64_t GetSizeOfCD() { return Field<8>().value; }
void SetSizeOfCD(std::uint64_t value) { Field<8>().value = value; }
std::uint64_t GetOffsetfStartOfCD() { return Field<9>().value; }
void SetOffsetfStartOfCD(std::uint64_t value) { Field<9>().value = value; }
private:
void SetSignature(std::uint32_t value) { Meta::Object::SetValue(Field(0), value); }
void SetGetSizeOfZip64CDRecord(std::uint64_t value) { Meta::Object::SetValue(Field(1), value); }
void SetVersionMadeBy(std::uint16_t value) { Meta::Object::SetValue(Field(2), value); }
void SetVersionNeededToExtract(std::uint16_t value) { Meta::Object::SetValue(Field(3), value); }
void SetNumberOfThisDisk(std::uint32_t value) { Meta::Object::SetValue(Field(4), value); }
void SetSignature(std::uint32_t value) { Field<0>().value = value; }
void SetGetSizeOfZip64CDRecord(std::uint64_t value) { Field<1>().value = value; }
void SetVersionMadeBy(std::uint16_t value) { Field<2>().value = value; }
void SetVersionNeededToExtract(std::uint16_t value) { Field<3>().value = value; }
void SetNumberOfThisDisk(std::uint32_t value) { Field<4>().value = value; }
StreamBase* m_stream = nullptr;
}; //class Zip64EndOfCentralDirectoryRecord
class Zip64EndOfCentralDirectoryLocator : public Meta::StructuredObject
class Zip64EndOfCentralDirectoryLocator : public Meta::StructuredObject<
Meta::Field4Bytes, // 0 - zip64 end of central dir locator signature 4 bytes(0x07064b50)
Meta::Field4Bytes, // 1 - number of the disk with the start of the zip64
// end of central directory 4 bytes
Meta::Field8Bytes, // 2 - relative offset of the zip64 end of central
// directory record 8 bytes
Meta::Field4Bytes // 3 - total number of disks 4 bytes
>
{
public:
Zip64EndOfCentralDirectoryLocator(StreamBase* s) : Meta::StructuredObject(
Zip64EndOfCentralDirectoryLocator(StreamBase* s) : m_stream(s)
{
// 0 - zip64 end of central dir locator signature 4 bytes(0x07064b50)
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<0>().validation = [](std::uint32_t& v)
{ if (v != static_cast<std::uint32_t>(Signatures::Zip64EndOfCDLocator))
{ throw ZipException("end of central directory locator does not match signature", ZipException::Error::InvalidHeader);
}
}),
};
// 1 - number of the disk with the start of the zip64 end of central directory 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<1>().validation = [](std::uint32_t& v)
{ if (v != 0)
{ throw ZipException("Invalid disk number", ZipException::Error::InvalidZip64CentralDirectoryLocator);
}
}),
};
// 2 - relative offset of the zip64 end of central directory record 8 bytes
std::make_shared<Meta::Field8Bytes>([&](std::uint64_t& v)
Field<2>().validation = [&](std::uint64_t& v)
{ if ((v == 0) ||
(v >= m_stream->Ftell()))
{ throw ZipException("Invalid relative offset", ZipException::Error::InvalidZip64CentralDirectoryLocator);
}
}),
};
// 3 - total number of disks 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<3>().validation = [](std::uint32_t& v)
{ if (v != 1)
{ throw ZipException("Invalid total number of disks", ZipException::Error::InvalidZip64CentralDirectoryLocator);
}
})
}), m_stream(s)
{/*constructor*/
};
SetSignature(static_cast<std::uint32_t>(Signatures::Zip64EndOfCDLocator));
SetNumberOfDisk(0);
SetTotalNumberOfDisks(1);
}
std::uint64_t GetRelativeOffset() { return *Meta::Object::GetValue<std::uint64_t>(Field(2)); }
void SetRelativeOffset(std::uint64_t value) { Meta::Object::SetValue(Field(2), value); }
std::uint64_t GetRelativeOffset() { return Field<2>().value; }
void SetRelativeOffset(std::uint64_t value) { Field<2>().value = value; }
private:
void SetSignature(std::uint32_t value) { Meta::Object::SetValue(Field(0), value); }
void SetNumberOfDisk(std::uint32_t value) { Meta::Object::SetValue(Field(1), value); }
void SetTotalNumberOfDisks(std::uint32_t value) { Meta::Object::SetValue(Field(3), value); }
void SetSignature(std::uint32_t value) { Field<0>().value = value; }
void SetNumberOfDisk(std::uint32_t value) { Field<1>().value = value; }
void SetTotalNumberOfDisks(std::uint32_t value) { Field<3>().value = value; }
StreamBase* m_stream = nullptr;
}; //class Zip64EndOfCentralDirectoryLocator
class EndCentralDirectoryRecord : public Meta::StructuredObject
class EndCentralDirectoryRecord : public Meta::StructuredObject<
Meta::Field4Bytes, // 0 - end of central dir signature 4 bytes (0x06054b50)
Meta::Field2Bytes, // 1 - number of this disk 2 bytes
Meta::Field2Bytes, // 2 - number of the disk with the start of the
// central directory 2 bytes
Meta::Field2Bytes, // 3 - total number of entries in the central
// directory on this disk 2 bytes
Meta::Field2Bytes, // 4 - total number of entries in the central
// directory 2 bytes
Meta::Field4Bytes, // 5 - size of the central directory 4 bytes
Meta::Field4Bytes, // 6 - offset of start of central directory with
// respect to the starting disk number 4 bytes
Meta::Field2Bytes, // 7 - .ZIP file comment length 2 bytes
Meta::FieldNBytes // 8 - .ZIP file comment (variable size)
>
{
public:
EndCentralDirectoryRecord() : Meta::StructuredObject(
EndCentralDirectoryRecord()
{
// 0 - end of central dir signature 4 bytes (0x06054b50)
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<0>().validation = [](std::uint32_t& v)
{ if (v != static_cast<std::uint32_t>(Signatures::EndOfCentralDirectory))
{ throw ZipException("invalid signiture", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 1 - number of this disk 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
Field<1>().validation = [](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported disk number", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 2 - number of the disk with the start of the central directory 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
Field<2>().validation = [](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("unsupported EoCDR disk number", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 3 - total number of entries in the central directory on this disk 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
Field<3>().validation = [](std::uint16_t& v)
{ if (v != std::numeric_limits<std::uint16_t>::max())
{ throw ZipException("unsupported total number of entries on this disk", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 4 - total number of entries in the central directory 2 bytes
std::make_shared<Meta::Field2Bytes>([](std::uint16_t& v)
Field<4>().validation = [](std::uint16_t& v)
{ if (v != std::numeric_limits<std::uint16_t>::max())
{ throw ZipException("unsupported total number of entries", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 5 - size of the central directory 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<5>().validation = [](std::uint32_t& v)
{ if (v != std::numeric_limits<std::uint32_t>::max())
{ throw ZipException("unsupported size of central directory", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 6 - offset of start of central directory with respect to the starting disk number 4 bytes
std::make_shared<Meta::Field4Bytes>([](std::uint32_t& v)
Field<6>().validation = [](std::uint32_t& v)
{ if (v != std::numeric_limits<std::uint32_t>::max())
{ throw ZipException("unsupported offset of start of central directory", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 7 - .ZIP file comment length 2 bytes
std::make_shared<Meta::Field2Bytes>([&](std::uint16_t& v)
Field<7>().validation = [&](std::uint16_t& v)
{ if (v != 0)
{ throw ZipException("Zip comment unsupported", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
}),
};
// 8 - .ZIP file comment (variable size)
std::make_shared<Meta::FieldNBytes>([](std::vector<std::uint8_t>& data)
Field<8>().validation = [](std::vector<std::uint8_t>& data)
{ if (data.size() != 0)
{ throw ZipException("Zip comment unsupported", ZipException::Error::InvalidEndOfCentralDirectoryRecord);
}
})
})
{/*constructor*/
};
SetSignature(static_cast<std::uint32_t>(Signatures::EndOfCentralDirectory));
SetNumberOfDisk(0);
SetDiskStart(0);
@ -378,45 +743,71 @@ namespace xPlat {
}
private:
void SetSignature(std::uint32_t value) { Meta::Object::SetValue(Field(0), value); }
void SetNumberOfDisk(std::uint16_t value) { Meta::Object::SetValue(Field(1), value); }
void SetDiskStart(std::uint16_t value) { Meta::Object::SetValue(Field(2), value); }
void SetTotalNumberOfEntries(std::uint16_t value) { Meta::Object::SetValue(Field(3), value); }
void SetTotalEntriesInCentralDirectory(std::uint16_t value) { Meta::Object::SetValue(Field(4), value); }
void SetSizeOfCentralDirectory(std::uint32_t value) { Meta::Object::SetValue(Field(5), value); }
void SetOffsetOfCentralDirectory(std::uint32_t value) { Meta::Object::SetValue(Field(6), value); }
void SetCommentLength(std::uint16_t value) { Meta::Object::SetValue(Field(7), value); }
void SetSignature(std::uint32_t value) { Field<0>().value = value; }
void SetNumberOfDisk(std::uint16_t value) { Field<1>().value = value; }
void SetDiskStart(std::uint16_t value) { Field<2>().value = value; }
void SetTotalNumberOfEntries(std::uint16_t value) { Field<3>().value = value; }
void SetTotalEntriesInCentralDirectory(std::uint16_t value) { Field<4>().value = value; }
void SetSizeOfCentralDirectory(std::uint32_t value) { Field<5>().value = value; }
void SetOffsetOfCentralDirectory(std::uint32_t value) { Field<6>().value = value; }
void SetCommentLength(std::uint16_t value) { Field<7>().value = value; }
};//class EndOfCentralDirectoryRecord
void ZipObject::Read()
ZipObject::ZipObject(StreamBase* stream)
{
// Confirm that the file IS the correct format
EndCentralDirectoryRecord endCentralDirectoryRecord;
m_stream->Seek(-1 * endCentralDirectoryRecord.Size(), StreamBase::Reference::END);
endCentralDirectoryRecord.Read(m_stream.get());
stream->Seek(-1 * endCentralDirectoryRecord.Size(), StreamBase::Reference::END);
endCentralDirectoryRecord.Read(stream);
// find where the zip central directory exists.
Zip64EndOfCentralDirectoryLocator zip64Locator(m_stream.get());
m_stream->Seek(-1*(endCentralDirectoryRecord.Size() + zip64Locator.Size()), StreamBase::Reference::END);
zip64Locator.Read(m_stream.get());
Zip64EndOfCentralDirectoryLocator zip64Locator(stream);
stream->Seek(-1*(endCentralDirectoryRecord.Size() + zip64Locator.Size()), StreamBase::Reference::END);
zip64Locator.Read(stream);
// now read the zip central directory
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectory(m_stream.get());
m_stream->Seek(zip64Locator.GetRelativeOffset(), StreamBase::Reference::START);
zip64EndOfCentralDirectory.Read(m_stream.get());
m_stream->Seek(zip64EndOfCentralDirectory.GetOffsetfStartOfCD(), StreamBase::Reference::START);
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectory(stream);
stream->Seek(zip64Locator.GetRelativeOffset(), StreamBase::Reference::START);
zip64EndOfCentralDirectory.Read(stream);
// read the zip central directory
stream->Seek(zip64EndOfCentralDirectory.GetOffsetfStartOfCD(), StreamBase::Reference::START);
for (std::uint32_t index = 0; index < zip64EndOfCentralDirectory.GetTotalNumberOfEntries(); index++)
{
auto centralFileHeader = std::make_shared<CentralDirectoryFileHeader>(m_stream.get());
centralFileHeader->Read(m_stream.get());
auto centralFileHeader = std::make_shared<CentralDirectoryFileHeader>(stream);
centralFileHeader->Read(stream);
// TODO: ensure that there are no collisions on name!
m_centralDirectory.insert(std::make_pair(centralFileHeader->GetFileName(), centralFileHeader));
}
// We should have no data between the end of the last central directory header and the start of the EoCD
if (m_stream->Ftell() != zip64Locator.GetRelativeOffset())
if (stream->Ftell() != zip64Locator.GetRelativeOffset())
{ throw ZipException("hidden data unsupported", ZipException::Error::HiddenDataBetweenLastCDHandEoCD);
}
// read the file repository
for (auto centralFileHeader : m_centralDirectory)
{
stream->Seek(centralFileHeader.second->GetRelativeOffsetOfLocalHeader(), xPlat::StreamBase::Reference::START);
auto localFileHeader = std::make_shared<LocalFileHeader>(centralFileHeader.second);
localFileHeader->Read(stream);
m_fileRepository.insert(std::make_pair(
centralFileHeader.second->GetRelativeOffsetOfLocalHeader(),
localFileHeader));
auto zipFileStream = std::make_shared<ZipFileStream>(
centralFileHeader.second->GetFileName(),
centralFileHeader.second->GetRelativeOffsetOfLocalHeader() + localFileHeader->Size(),
localFileHeader->GetCompressedSize(),
localFileHeader->GetUncompressedSize(),
localFileHeader->GetCompressionType() == CompressionType::Deflate
);
m_streams.insert(std::make_pair(
centralFileHeader.second->GetFileName(),
zipFileStream));
}
}
std::vector<std::string> ZipObject::GetFileNames()
@ -429,4 +820,4 @@ namespace xPlat {
return result;
}
} // namespace xPlat
} // namespace xPlat

Просмотреть файл

@ -53,10 +53,11 @@ XPLATAPPX_API unsigned int UnpackAppx(char* source, char* destination)
{
return ResultOf(source, destination, [&]() {
std::string appxFileName(source);
xPlat::ZipObject zip(std::make_unique<xPlat::FileStream>(
auto rawFile = std::make_unique<xPlat::FileStream>(
std::move(appxFileName),
xPlat::FileStream::Mode::READ));
zip.Read();
xPlat::FileStream::Mode::READ);
xPlat::ZipObject zip(rawFile.get());
});
}