Everything except for translating file name(s) through the IAppxFile interface into a platform correct/compatible name.

This commit is contained in:
Phil Smith 2017-11-06 17:32:40 -08:00
Родитель bd809cac18
Коммит 545d12bf54
22 изменённых файлов: 339 добавлений и 216 удалений

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

@ -16,11 +16,8 @@
to non Win32 clients, CreateStreamOnFile is provided to enable easier consumption of the COM APIs.
0.7 - API changes:
* Implemented IAppxFactory's CreatePackageWriter, and CreatePackageReader methods.
* Implemented IAppxPackageReader's GetPayloadFiles
* Implemented IAppxFileEnumerator
* Implemented IAppxFactory's CreatePackageReader, IAppxPackageReader's GetPayloadFiles, and
Implemented IAppxFileEnumerator. Basically, everything used in ExtractContentsSample
* Moved utf8/utf16 conversion functions into their own header to support marshalling
out file Names and content types to clients through the nanoCOM layer.

0
ZipObject.cpp Normal file
Просмотреть файл

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

@ -5,7 +5,7 @@
#include <codecvt>
#ifdef WIN32
#define UNICODE = 1
#define UNICODE
#include <windows.h>
#else
// required posix-specific headers
@ -29,10 +29,13 @@ public:
template<
class U,
typename = typename std::enable_if<
std::is_convertible<U*,T*>::value || std::is_same<U,T>::value
std::is_convertible<U*,T*>::value
>::type
>
ComPtr(U* ptr) : m_ptr(ptr) { InternalAddRef(); }
ComPtr(U* ptr) : m_ptr(ptr) { }
// Distinct from above, this is where ComPtr<T> t = Foo(...) where Foo returns T*
ComPtr(T* ptr) : m_ptr(ptr) { InternalAddRef(); }
// copy ctor
ComPtr(const ComPtr& right) : m_ptr(right.m_ptr) { InternalAddRef(); }
@ -41,20 +44,12 @@ public:
template<
class U,
typename = typename std::enable_if<
std::is_convertible<U*,T*>::value || std::is_same<U,T>::value
std::is_convertible<U*,T*>::value
>::type
>
ComPtr(const ComPtr<U>& right) : m_ptr(right.m_ptr) { InternalAddRef(); }
// move ctor
ComPtr(ComPtr &&right) : m_ptr(nullptr)
{
if (this != reinterpret_cast<ComPtr*>(&reinterpret_cast<std::int8_t&>(right)))
{ Swap(right);
}
}
// move ctor that allows instantiation of a class when U* is convertible to T*
// move ctor that allows instantiation of a class when U* is convertible to T*
template<
class U,
typename = typename std::enable_if<
@ -75,17 +70,16 @@ public:
return *this;
}
// Assignment operator... VERY important.
ComPtr& operator=(const ComPtr& right)
{
if (m_ptr != right.m_ptr) { ComPtr(right).Swap(*this); }
ComPtr& operator=(ComPtr &&right)
{
ComPtr(std::move(right)).Swap(*this);
return *this;
}
// Assignment operator of T*
ComPtr& operator=(T* right)
{
if (m_ptr != right) { ComPtr(right).Swap(*this); }
// Assignment operator...
ComPtr& operator=(const ComPtr& right)
{
if (m_ptr != right.m_ptr) { ComPtr(right).Swap(*this); }
return *this;
}
@ -98,13 +92,7 @@ public:
>
ComPtr& operator=(U* right)
{
ComPtr(right).Swap(*this);
return *this;
}
ComPtr& operator=(ComPtr &&right)
{
ComPtr(std::move(right)).Swap(*this);
if (m_ptr != right) { ComPtr(right).Swap(*this); }
return *this;
}
@ -112,12 +100,25 @@ public:
inline T* operator->() const { return m_ptr; }
inline T* Get() const { return m_ptr; }
inline T* Detach()
{ T* temp = m_ptr;
m_ptr = nullptr;
return temp;
}
inline T** operator&()
{ InternalRelease();
return &m_ptr;
}
template <class U>
inline ComPtr<U> As()
{
ComPtr<U> out;
ThrowHrIfFailed(m_ptr->QueryInterface(UuidOfImpl<U>::iid, reinterpret_cast<void**>(&out)));
return out;
}
protected:
T* m_ptr = nullptr;
@ -156,7 +157,7 @@ std::wstring utf8_to_utf16(const std::string& utf8string)
#ifdef WIN32
int mkdirp(std::wstring& utf16Path)
{
for (int i = 0; i < fullFileName.size(); i++)
for (int i = 0; i < utf16Path.size(); i++)
{
if (utf16Path[i] == L'\0')
{
@ -228,9 +229,7 @@ const FootprintFilesType footprintFilesType[FootprintFilesCount] = {
//
// Helper function to create a writable IStream over a file with the specified name
// under the specified path. This function will also create intermediate
// subdirectories if necessary. For simplicity, file names including path are
// assumed to be 200 characters or less. A real application should be able to
// handle longer names and allocate the necessary buffer dynamically.
// subdirectories if necessary.
//
// Parameters:
// path - Path of the folder containing the file to be opened. This should NOT
@ -254,6 +253,10 @@ HRESULT GetOutputStream(LPCWSTR path, LPCWSTR fileName, IStream** stream)
return hr;
}
// Or you can use what-ever allocator/deallocator is best for your platform...
LPVOID STDMETHODCALLTYPE MyAllocate(SIZE_T cb) { return std::malloc(cb); }
void STDMETHODCALLTYPE MyFree(LPVOID pv) { std::free(pv); }
//
// Creates a cross-plat app package.
//
@ -272,9 +275,12 @@ HRESULT GetPackageReader(LPCWSTR inputFileName, IAppxPackageReader** package)
hr = CreateStreamOnFileUTF16(inputFileName, true, &inputStream);
if (SUCCEEDED(hr))
{
// On Win32 platforms CoCreateAppxFactory defaults to CoTaskMemAlloc/CoTaskMemFree
// On non-Win32 platforms CoCreateAppxFactory will return 0x80070032 (e.g. HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED))
// So on all platforms, it's always safe to call CoCreateAppxFactoryWithHeap, just be sure to bring your own heap!
hr = CoCreateAppxFactoryWithHeap(
std::malloc,
std::free,
MyAllocate,
MyFree,
APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_SKIPAPPXMANIFEST,
&appxFactory);

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

@ -1,9 +1,33 @@
#include "ComHelper.hpp"
#pragma once
#include "AppxPackaging.hpp"
#include "UnicodeConversion.hpp"
#include "AppxWindows.hpp"
#include "ComHelper.hpp"
#include <string>
// internal interface
EXTERN_C const IID IID_IxPlatFactory;
#ifndef WIN32
MIDL_INTERFACE("1f850db4-32b8-4db6-8bf4-5a897eb611f1")
interface IxPlatFactory : public IUnknown
#else
#include "UnKnwn.h"
#include "Objidl.h"
class IxPlatFactory : public IUnknown
#endif
{
public:
#ifdef WIN32
virtual ~IxPlatFactory() {}
#endif
virtual HRESULT MarshalOutString(std::string& internal, LPWSTR *result) = 0;
};
SpecializeUuidOfImpl(IxPlatFactory);
namespace xPlat {
class AppxFactory : public xPlat::ComClass<AppxFactory, IAppxFactory>
class AppxFactory : public ComClass<AppxFactory, IxPlatFactory, IAppxFactory>
{
public:
AppxFactory(APPX_VALIDATION_OPTION validationOptions, COTASKMEMALLOC* memalloc, COTASKMEMFREE* memfree ) :
@ -13,77 +37,22 @@ namespace xPlat {
}
// IAppxFactory
HRESULT STDMETHODCALLTYPE CreatePackageWriter(
HRESULT STDMETHODCALLTYPE CreatePackageWriter (
IStream* outputStream,
APPX_PACKAGE_SETTINGS* ,//settings, TODO: plumb this through
IAppxPackageWriter** packageWriter)
{
return static_cast<HRESULT>(Error::NotImplemented);
// return xPlat::ResultOf([&]() {
// ThrowErrorIf(Error::InvalidParameter, (packageWriter == nullptr || *packageWriter != nullptr), "Invalid parameter");
// ComPtr<IStorageObject> zip(new xPlat::ZipObject(outputStream));
// ComPtr<IAppxPackageWriter> result(new AppxPackageObject(m_validationOptions, zip.Get()));
// *packageWriter = result.Get();
// });
}
IAppxPackageWriter** packageWriter);
HRESULT STDMETHODCALLTYPE CreatePackageReader(
IStream* inputStream,
IAppxPackageReader** packageReader)
{
return xPlat::ResultOf([&]() {
ThrowErrorIf(Error::InvalidParameter, (packageReader == nullptr || *packageReader != nullptr), "Invalid parameter");
ComPtr<IStorageObject> zip(new xPlat::ZipObject(inputStream));
ComPtr<IAppxPackageReader> result(new AppxPackageObject(m_validationOptions, zip.Get()));
*packageReader = result.Get();
});
}
HRESULT STDMETHODCALLTYPE CreatePackageReader (IStream* inputStream, IAppxPackageReader** packageReader) override;
HRESULT STDMETHODCALLTYPE CreateManifestReader(IStream* inputStream, IAppxManifestReader** manifestReader) override ;
HRESULT STDMETHODCALLTYPE CreateBlockMapReader (IStream* inputStream, IAppxBlockMapReader** blockMapReader) override;
HRESULT STDMETHODCALLTYPE CreateManifestReader(
IStream* inputStream,
IAppxManifestReader** manifestReader)
{
return xPlat::ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
});
}
HRESULT STDMETHODCALLTYPE CreateBlockMapReader(
IStream* inputStream,
IAppxBlockMapReader** blockMapReader)
{
return xPlat::ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
});
}
HRESULT STDMETHODCALLTYPE CreateValidatedBlockMapReader(
HRESULT STDMETHODCALLTYPE CreateValidatedBlockMapReader (
IStream* blockMapStream,
LPCWSTR signatureFileName,
IAppxBlockMapReader** blockMapReader)
{
return xPlat::ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
});
}
IAppxBlockMapReader** blockMapReader) override;
HRESULT MarshalOutString(std::string& internal, LPWSTR *result)
{
return xPlat::ResultOf([&]() {
ThrowErrorIf(Error::InvalidParameter, (result == nullptr || *result != nullptr), "bad pointer" );
auto intermediate = utf8_to_utf16(internal);
std::size_t countBytes = sizeof(wchar_t)*(internal.size()+1);
*result = reinterpret_cast<LPWSTR>(m_memalloc(countBytes));
ThrowErrorIfNot(Error::OutOfMemory, (*result), "Allocation failed!");
std::memset(reinterpret_cast<void*>(*result), 0, countBytes);
std::memcpy(reinterpret_cast<void*>(*result),
reinterpret_cast<void*>(const_cast<wchar_t*>(intermediate.c_str())),
countBytes - sizeof(wchar_t));
});
}
// IxPlatFactory
HRESULT MarshalOutString(std::string& internal, LPWSTR *result) override;
COTASKMEMALLOC* m_memalloc;
COTASKMEMFREE* m_memfree;

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

@ -19,10 +19,20 @@
// internal interface
EXTERN_C const IID IID_IAppxPackage;
#ifndef WIN32
MIDL_INTERFACE("51b2c456-aaa9-46d6-8ec9-298220559189")
interface IAppxPackage : public IUnknown
#else
#include "Unknwn.h"
#include "Objidl.h"
class IAppxPackage : public IUnknown
#endif
{
public:
#ifdef WIN32
virtual ~IAppxPackage() {}
#endif
virtual void Pack(APPX_PACKUNPACK_OPTION options, const std::string& certFile, IStorageObject* from) = 0;
virtual void Unpack(APPX_PACKUNPACK_OPTION options, IStorageObject* to) = 0;
virtual std::vector<std::string>& GetFootprintFiles() = 0;
@ -142,7 +152,7 @@ namespace xPlat {
{ return ResultOf([&]{
ThrowErrorIf(Error::InvalidParameter,(file == nullptr || *file != nullptr), "bad pointer");
ThrowErrorIf(Error::Unexpected, (m_cursor >= m_files.size()), "index out of range");
*file = ComPtr<IStream>(m_storage->GetFile(m_files[m_cursor])).As<IAppxFile>().Get();
*file = ComPtr<IStream>(m_storage->GetFile(m_files[m_cursor])).As<IAppxFile>().Detach();
});
}

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

@ -14,16 +14,15 @@
// and what is requiered if the interfaces change.
/* Forward Declarations */
#ifndef __appxpackaging_hpp__
#define __appxpackaging_hpp__
#include "AppxWindows.hpp"
#ifdef WIN32
#include <AppxPackaging.h>
#else
#include "AppxWindows.hpp"
// Interfaces
interface IUnknown;
interface ISequentialStream;
@ -1978,8 +1977,8 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE ValidateAppxSignature(char* appx);
// A call to called CoCreateAppxFactory is required before start using the factory on non-windows platforms specifying
// their allocator/de-allocator pair of preference. Failure to do this will result on E_UNEXPECTED.
typedef void* STDMETHODCALLTYPE COTASKMEMALLOC(size_t cb);
typedef void STDMETHODCALLTYPE COTASKMEMFREE(void* pv);
typedef LPVOID STDMETHODCALLTYPE COTASKMEMALLOC(SIZE_T cb);
typedef void STDMETHODCALLTYPE COTASKMEMFREE(LPVOID pv);
// Call specific for Windows. Default to call CoTaskMemAlloc and CoTaskMemFree
XPLATAPPX_API HRESULT STDMETHODCALLTYPE CoCreateAppxFactory(

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

@ -11,6 +11,10 @@
#define XPLATAPPX_API extern "C" __declspec(dllexport)
// UNICODE MUST be defined before you include Windows.h if you want the non-ascii versions of APIs (and you do)
#ifdef UNICODE
#undef UNICODE
#endif
#define UNICODE
#define NOMINMAX
#include <windows.h>
@ -47,6 +51,8 @@
typedef const WCHAR* LPCWSTR;
typedef char BYTE;
typedef int BOOL;
typedef size_t SIZE_T;
typedef void* LPVOID;
#ifndef FALSE
#define FALSE 0

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

@ -50,10 +50,13 @@ namespace xPlat {
template<
class U,
typename = typename std::enable_if<
std::is_convertible<U*,T*>::value || std::is_same<U,T>::value
std::is_convertible<U*,T*>::value
>::type
>
ComPtr(U* ptr) : m_ptr(ptr) { InternalAddRef(); }
ComPtr(U* ptr) : m_ptr(ptr) { }
// Distinct from above, this is where ComPtr<T> t = Foo(...) where Foo returns T*
ComPtr(T* ptr) : m_ptr(ptr) { InternalAddRef(); }
// copy ctor
ComPtr(const ComPtr& right) : m_ptr(right.m_ptr) { InternalAddRef(); }
@ -62,20 +65,12 @@ namespace xPlat {
template<
class U,
typename = typename std::enable_if<
std::is_convertible<U*,T*>::value || std::is_same<U,T>::value
std::is_convertible<U*,T*>::value
>::type
>
ComPtr(const ComPtr<U>& right) : m_ptr(right.m_ptr) { InternalAddRef(); }
// move ctor
ComPtr(ComPtr &&right) : m_ptr(nullptr)
{
if (this != reinterpret_cast<ComPtr*>(&reinterpret_cast<std::int8_t&>(right)))
{ Swap(right);
}
}
// move ctor that allows instantiation of a class when U* is convertible to T*
// move ctor that allows instantiation of a class when U* is convertible to T*
template<
class U,
typename = typename std::enable_if<
@ -96,17 +91,16 @@ namespace xPlat {
return *this;
}
// Assignment operator... VERY important.
ComPtr& operator=(const ComPtr& right)
{
if (m_ptr != right.m_ptr) { ComPtr(right).Swap(*this); }
ComPtr& operator=(ComPtr &&right)
{
ComPtr(std::move(right)).Swap(*this);
return *this;
}
// Assignment operator of T*
ComPtr& operator=(T* right)
{
if (m_ptr != right) { ComPtr(right).Swap(*this); }
// Assignment operator...
ComPtr& operator=(const ComPtr& right)
{
if (m_ptr != right.m_ptr) { ComPtr(right).Swap(*this); }
return *this;
}
@ -119,13 +113,7 @@ namespace xPlat {
>
ComPtr& operator=(U* right)
{
ComPtr(right).Swap(*this);
return *this;
}
ComPtr& operator=(ComPtr &&right)
{
ComPtr(std::move(right)).Swap(*this);
if (m_ptr != right) { ComPtr(right).Swap(*this); }
return *this;
}
@ -133,6 +121,12 @@ namespace xPlat {
inline T* operator->() const { return m_ptr; }
inline T* Get() const { return m_ptr; }
inline T* Detach()
{ T* temp = m_ptr;
m_ptr = nullptr;
return temp;
}
inline T** operator&()
{ InternalRelease();

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

@ -29,5 +29,5 @@ namespace xPlat {
std::map<std::string, ComPtr<IStream>> m_streams;
std::string m_root;
};//class ZipObject
};//class DirectoryObject
}

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

@ -18,13 +18,14 @@ namespace xPlat {
//
// Win32 error codes
//
OK = 0,
OK = 0x00000000,
NotImplemented = 0x80004001,
NoInterface = 0x80004002,
Unexpected = 0x8000ffff,
FileNotFound = 0x80070002,
OutOfMemory = 0x8007000E,
NotSupported = 0x80070032,
InvalidParameter = 0x80070057,
NotImplemented = 0x80070078,
OutOfMemory = 0x80000002,
Unexpected = 0x8000ffff,
NoInterface = 0x80000004,
//
// xPlat specific error codes
@ -50,15 +51,17 @@ namespace xPlat {
InflateInitialize = ERROR_FACILITY + 0x0021,
InflateRead = ERROR_FACILITY + 0x0022,
InflateCorruptData = ERROR_FACILITY + 0x0023,
// Signature errors
AppxSignatureInvalid = ERROR_FACILITY + 0x0030,
// AppxPackage format errors
AppxMissingSignatureP7X = ERROR_FACILITY + 0x0031,
AppxMissingContentTypesXML = ERROR_FACILITY + 0x0032,
AppxMissingBlockMapXML = ERROR_FACILITY + 0x0033,
AppxMissingAppxManifestXML = ERROR_FACILITY + 0x0034,
AppxDuplicateFootprintFile = ERROR_FACILITY + 0x0035,
// Signature errors
AppxSignatureInvalid = ERROR_FACILITY + 0x0041,
};
// Defines a common exception type to throw in exceptional cases. DO NOT USE FOR FLOW CONTROL!

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

@ -63,8 +63,9 @@ namespace xPlat {
HRESULT STDMETHODCALLTYPE GetSize(UINT64* size) override
{
if (size) { *size = m_size; }
return static_cast<HRESULT>(Error::OK);
return ResultOf([&]{
if (size) { *size = m_size; }
});
}
std::uint64_t Size() { return m_size; }

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

@ -11,10 +11,20 @@
// internal interface
EXTERN_C const IID IID_IStorageObject;
#ifndef WIN32
MIDL_INTERFACE("ec25b96e-0db1-4483-bdb1-cab1109cb741")
interface IStorageObject : public IUnknown
#else
#include "Unknwn.h"
#include "Objidl.h"
class IStorageObject : public IUnknown
#endif
{
public:
public:
#ifdef WIN32
virtual ~IStorageObject() {}
#endif
virtual std::string GetPathSeparator() = 0;
// Obtains a vector of UTF-8 formatted string names contained in the storage object

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

@ -1,39 +1,13 @@
#include <memory>
#include <iostream>
#pragma once
#include <string>
#include <sstream>
#include <locale>
#include <codecvt>
namespace xPlat {
std::wstring utf8_to_utf16(const std::string& utf8string)
{
/*
from: https://connect.microsoft.com/VisualStudio/feedback/details/1403302/unresolved-external-when-using-codecvt-utf8
Posted by Microsoft on 2/16/2016 at 11:49 AM
<snip>
A workaround is to replace 'char32_t' with 'unsigned int'. In VS2013, char32_t was a typedef of 'unsigned int'.
In VS2015, char32_t is a distinct type of it's own. Switching your use of 'char32_t' to 'unsigned int' will get
you the old behavior from earlier versions and won't trigger a missing export error.
// converts an input utf8 formatted string into a utf16 formatted string
std::wstring utf8_to_utf16(const std::string& utf8string);
There is also a similar error to this one with 'char16_t' that can be worked around using 'unsigned short'.
<snip>
*/
#ifdef WIN32
auto converted = std::wstring_convert<std::codecvt_utf8_utf16<unsigned short>, unsigned short>{}.from_bytes(utf8string.data());
#else
auto converted = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(utf8string.data());
#endif
std::wstring result(converted.begin(), converted.end());
return result;
}
std::string utf16_to_utf8(const std::wstring& utf16string)
{
auto converted = std::wstring_convert<std::codecvt_utf8<wchar_t>>{}.to_bytes(utf16string.data());
std::string result(converted.begin(), converted.end());
return result;
}
// converts an input utf16 formatted string into a utf8 formatted string
std::string utf16_to_utf8(const std::wstring& utf16string);
} // namespace xPlat

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

@ -3,6 +3,7 @@
#include "ComHelper.hpp"
#include "StreamBase.hpp"
#include "RangeStream.hpp"
#include "AppxFactory.hpp"
#include <string>
@ -14,24 +15,25 @@ namespace xPlat {
public:
// TODO: define what streams to pass in on the .ctor
ZipFileStream(
std::string name,
std::string contentType,
IxPlatFactory* factory,
bool isCompressed,
std::uint32_t offset,
std::uint32_t size,
IStream* stream
) : m_isCompressed(isCompressed), RangeStream(offset, size, stream)
) : m_isCompressed(isCompressed), RangeStream(offset, size, stream), m_name(name), m_contentType(contentType), m_factory(factory)
{
}
HRESULT STDMETHODCALLTYPE GetName(LPWSTR* fileName) override
{
// TODO: Implement here.
return static_cast<HRESULT>(Error::NotImplemented);
return m_factory->MarshalOutString(m_name, fileName);
}
HRESULT STDMETHODCALLTYPE GetContentType(LPWSTR* contentType) override
{
// TODO: Implement here.
return static_cast<HRESULT>(Error::NotImplemented);
return m_factory->MarshalOutString(m_name, contentType);
}
HRESULT STDMETHODCALLTYPE GetCompressionOption(APPX_COMPRESSION_OPTION* compressionOption) override
@ -43,6 +45,9 @@ namespace xPlat {
inline bool IsCompressed() { return m_isCompressed; }
protected:
bool m_isCompressed = false;
ComPtr<IxPlatFactory> m_factory;
std::string m_name;
std::string m_contentType;
bool m_isCompressed = false;
};
}

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

@ -4,21 +4,18 @@
#include "ComHelper.hpp"
#include "StreamBase.hpp"
#include "StorageObject.hpp"
#include "AppxFactory.hpp"
#include <vector>
#include <map>
#include <memory>
namespace xPlat {
// forward declarations
class CentralDirectoryFileHeader;
class LocalFileHeader;
// This represents a raw stream over a.zip file.
class ZipObject : public ComClass<ZipObject, IStorageObject>
{
public:
ZipObject(IStream* stream);
ZipObject(IxPlatFactory* appxFactory, IStream* stream);
// StorageObject methods
std::string GetPathSeparator() override;
@ -29,6 +26,7 @@ namespace xPlat {
void CommitChanges() override;
protected:
ComPtr<IxPlatFactory> m_factory;
ComPtr<IStream> m_stream;
std::map<std::string, ComPtr<IStream>> m_streams;
};//class ZipObject

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

@ -0,0 +1,77 @@
#include "AppxFactory.hpp"
#include "UnicodeConversion.hpp"
#include "Exceptions.hpp"
#include "ZipObject.hpp"
#include "AppxPackageObject.hpp"
namespace xPlat {
// IAppxFactory
HRESULT STDMETHODCALLTYPE AppxFactory::CreatePackageWriter (
IStream* outputStream,
APPX_PACKAGE_SETTINGS* ,//settings, TODO: plumb this through
IAppxPackageWriter** packageWriter)
{
return static_cast<HRESULT>(Error::NotImplemented);
}
HRESULT STDMETHODCALLTYPE AppxFactory::CreatePackageReader (
IStream* inputStream,
IAppxPackageReader** packageReader)
{
return ResultOf([&]() {
ThrowErrorIf(Error::InvalidParameter, (packageReader == nullptr || *packageReader != nullptr), "Invalid parameter");
ComPtr<IxPlatFactory> self;
ThrowHrIfFailed(QueryInterface(UuidOfImpl<IxPlatFactory>::iid, reinterpret_cast<void**>(&self)));
ComPtr<IStorageObject> zip(new ZipObject(self.Get(), inputStream));
ComPtr<IAppxPackageReader> result(new AppxPackageObject(m_validationOptions, zip.Get()));
*packageReader = result.Detach();
});
}
HRESULT STDMETHODCALLTYPE AppxFactory::CreateManifestReader(
IStream* inputStream,
IAppxManifestReader** manifestReader)
{
return ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
});
}
HRESULT STDMETHODCALLTYPE AppxFactory::CreateBlockMapReader (
IStream* inputStream,
IAppxBlockMapReader** blockMapReader)
{
return ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
});
}
HRESULT STDMETHODCALLTYPE AppxFactory::CreateValidatedBlockMapReader (
IStream* blockMapStream,
LPCWSTR signatureFileName,
IAppxBlockMapReader** blockMapReader)
{
return ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
});
}
HRESULT AppxFactory::MarshalOutString(std::string& internal, LPWSTR *result)
{
return ResultOf([&]() {
ThrowErrorIf(Error::InvalidParameter, (result == nullptr || *result != nullptr), "bad pointer" );
auto intermediate = utf8_to_utf16(internal);
std::size_t countBytes = sizeof(wchar_t)*(internal.size()+1);
*result = reinterpret_cast<LPWSTR>(m_memalloc(countBytes));
ThrowErrorIfNot(Error::OutOfMemory, (*result), "Allocation failed!");
std::memset(reinterpret_cast<void*>(*result), 0, countBytes);
std::memcpy(reinterpret_cast<void*>(*result),
reinterpret_cast<void*>(const_cast<wchar_t*>(intermediate.c_str())),
countBytes - sizeof(wchar_t));
});
}
} // namespace xPlat

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

@ -4,9 +4,11 @@
#include "StreamBase.hpp"
#include "StorageObject.hpp"
#include "AppxPackageObject.hpp"
#include "UnicodeConversion.hpp"
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <functional>
#include <limits>
@ -20,6 +22,14 @@ namespace xPlat {
#define APPXSIGNATURE_P7X "AppxSignature.p7x"
#define CONTENT_TYPES_XML "[Content_Types].xml"
static const std::map<APPX_FOOTPRINT_FILE_TYPE, std::string> footprintFiles =
{
{APPX_FOOTPRINT_FILE_TYPE_MANIFEST, APPXMANIFEST_XML},
{APPX_FOOTPRINT_FILE_TYPE_BLOCKMAP, APPXBLOCKMAP_XML},
{APPX_FOOTPRINT_FILE_TYPE_SIGNATURE, APPXSIGNATURE_P7X},
{APPX_FOOTPRINT_FILE_TYPE_CODEINTEGRITY, CODEINTEGRITY_CAT},
};
AppxPackageId::AppxPackageId(
const std::string& name,
const std::string& version,
@ -169,20 +179,29 @@ namespace xPlat {
throw Exception(Error::NotImplemented);
});
}
HRESULT STDMETHODCALLTYPE AppxPackageObject::GetFootprintFile(APPX_FOOTPRINT_FILE_TYPE type, IAppxFile** file)
{
return xPlat::ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
ThrowErrorIf(Error::InvalidParameter, (file == nullptr || *file != nullptr), "bad pointer");
auto footprint = footprintFiles.find(type);
ThrowErrorIf(Error::FileNotFound, (footprint == footprintFiles.end()), "unknown footprint file type");
ComPtr<IStream> stream = GetFile(footprint->second);
ThrowErrorIf(Error::FileNotFound, (stream.Get() == nullptr), "requested footprint file not in package")
auto result = stream.As<IAppxFile>();
*file = result.Detach();
});
}
HRESULT STDMETHODCALLTYPE AppxPackageObject::GetPayloadFile(LPCWSTR fileName, IAppxFile** file)
{
return xPlat::ResultOf([&]() {
// TODO: Implement
throw Exception(Error::NotImplemented);
ThrowErrorIf(Error::InvalidParameter, (fileName == nullptr || file == nullptr || *file != nullptr), "bad pointer");
std::string name = utf16_to_utf8(fileName);
ComPtr<IStream> stream = GetFile(name);
ThrowErrorIf(Error::FileNotFound, (stream.Get() == nullptr), "requested file not in package")
auto result = stream.As<IAppxFile>();
*file = result.Detach();
});
}

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

@ -95,7 +95,7 @@ MIDL_DEFINE_GUID(IID, IID_IAppxPackageEditor,0xE2ADB6DC,0x5E71,0x4416,0x86,0xB6,
// internal interfaces.
MIDL_DEFINE_GUID(IID, IID_IAppxPackage,0x51B2C456,0xAAA9,0x46D6,0x8E,0xC9,0x29,0x82,0x20,0x55,0x91,0x89);
MIDL_DEFINE_GUID(IID, IID_IStorageObject,0xEC25B96E,0x0DB1,0x4483,0xBD,0xB1,0xCA,0xB1,0x10,0x9C,0xB7,0x41);
MIDL_DEFINE_GUID(IID, IID_IxPlatFactory, 0x1f850db4,0x32b8,0x4db6,0x8b,0xf4,0x5a,0x89,0x7e,0xb6,0x11,0xf1);
#undef MIDL_DEFINE_GUID
}

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

@ -71,10 +71,12 @@ set(LIB_PRIVATE_HEADERS
set(LIB_SOURCES
AppxBlockMapObject.cpp
AppxFactory.cpp
AppxPackageObject.cpp
AppxPackaging_i.cpp
AppxSignature.cpp
InflateStream.cpp
InflateStream.cpp
UnicodeConversion.cpp
xPlatAppx.cpp
ZipObject.cpp
${DirectoryObject}

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

@ -0,0 +1,37 @@
#include <memory>
#include <iostream>
#include <sstream>
#include <locale>
#include <codecvt>
#include "UnicodeConversion.hpp"
namespace xPlat {
std::wstring utf8_to_utf16(const std::string& utf8string)
{
/*
from: https://connect.microsoft.com/VisualStudio/feedback/details/1403302/unresolved-external-when-using-codecvt-utf8
Posted by Microsoft on 2/16/2016 at 11:49 AM
<snip>
A workaround is to replace 'char32_t' with 'unsigned int'. In VS2013, char32_t was a typedef of 'unsigned int'.
In VS2015, char32_t is a distinct type of it's own. Switching your use of 'char32_t' to 'unsigned int' will get
you the old behavior from earlier versions and won't trigger a missing export error.
There is also a similar error to this one with 'char16_t' that can be worked around using 'unsigned short'.
<snip>
*/
#ifdef WIN32
auto converted = std::wstring_convert<std::codecvt_utf8_utf16<unsigned short>, unsigned short>{}.from_bytes(utf8string.data());
#else
auto converted = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(utf8string.data());
#endif
std::wstring result(converted.begin(), converted.end());
return result;
}
std::string utf16_to_utf8(const std::wstring& utf16string)
{
auto converted = std::wstring_convert<std::codecvt_utf8<wchar_t>>{}.to_bytes(utf16string.data());
std::string result(converted.begin(), converted.end());
return result;
}
} // namespace xPlat

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

@ -720,6 +720,7 @@ namespace xPlat {
IStream* ZipObject::GetFile(const std::string& fileName)
{
// TODO: Make this on-demand populate m_streams and then pull from there.
return m_streams[fileName].Get();
}
@ -740,7 +741,7 @@ namespace xPlat {
std::string ZipObject::GetPathSeparator() { return "/"; }
ZipObject::ZipObject(IStream* stream) : m_stream(stream)
ZipObject::ZipObject(IxPlatFactory* appxFactory, IStream* stream) : m_factory(appxFactory), m_stream(stream)
{
// Confirm that the file IS the correct format
EndCentralDirectoryRecord endCentralDirectoryRecord;
@ -781,6 +782,7 @@ namespace xPlat {
// TODO: change to uint64_t when adding full zip64 support
std::map<std::uint32_t, std::shared_ptr<LocalFileHeader>> fileRepository;
// TODO: change population of m_streams into cache semantics and move into ZipObject::GetFile
// Read the file repository
for (const auto& centralFileHeader : centralDirectory)
{
@ -793,6 +795,9 @@ namespace xPlat {
localFileHeader));
ComPtr<IStream> fileStream (new ZipFileStream(
centralFileHeader.second->GetFileName(),
"TODO: Implement", // TODO: put value from content type
m_factory.Get(),
localFileHeader->GetCompressionType() == CompressionType::Deflate,
centralFileHeader.second->GetRelativeOffsetOfLocalHeader() + localFileHeader->Size(),
localFileHeader->GetCompressedSize(),
@ -807,4 +812,4 @@ namespace xPlat {
m_streams.insert(std::make_pair(centralFileHeader.second->GetFileName(), std::move(fileStream)));
}
} // ZipObject::ZipObject
} // namespace xPlat
} // namespace xPlat

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

@ -4,6 +4,7 @@
#include "RangeStream.hpp"
#include "ZipObject.hpp"
#include "DirectoryObject.hpp"
#include "UnicodeConversion.hpp"
#include "ComHelper.hpp"
#include "AppxPackaging.hpp"
#include "AppxPackageObject.hpp"
@ -11,6 +12,8 @@
#include <string>
#include <memory>
#include <cstdlib>
#include <functional>
#ifdef WIN32
#include <Objbase.h>
@ -129,6 +132,10 @@ static void finalizer(void) { // 3
#endif
LPVOID STDMETHODCALLTYPE InternalAllocate(SIZE_T cb) { return std::malloc(cb); }
void STDMETHODCALLTYPE InternalFree(LPVOID pv) { std::free(pv); }
XPLATAPPX_API HRESULT STDMETHODCALLTYPE UnpackAppx(
APPX_PACKUNPACK_OPTION packUnpackOptions,
APPX_VALIDATION_OPTION validationOption,
@ -144,7 +151,7 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE UnpackAppx(
xPlat::ComPtr<IAppxFactory> factory;
// We don't need to use the caller's heap here because we're not marshalling any strings
// out to the caller. So default to new / delete[] and be done with it!
ThrowHrIfFailed(CoCreateAppxFactoryWithHeap(std::malloc, std::free, validationOption, &factory));
ThrowHrIfFailed(CoCreateAppxFactoryWithHeap(InternalAllocate, InternalFree, validationOption, &factory));
xPlat::ComPtr<IStream> stream;
ThrowHrIfFailed(CreateStreamOnFile(utf8SourcePackage, true, &stream));
@ -175,7 +182,7 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE PackAppx(
ThrowHrIfFailed(CreateStreamOnFile(utf8Destination, false, &stream));
xPlat::ComPtr<IAppxFactory> factory;
ThrowHrIfFailed(CoCreateAppxFactoryWithHeap(std::malloc, std::free, validationOption, &factory));
ThrowHrIfFailed(CoCreateAppxFactoryWithHeap(InternalAllocate, InternalFree, validationOption, &factory));
// TODO: plumb these through
APPX_PACKAGE_SETTINGS option {0};
@ -192,7 +199,16 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE ValidateAppxSignature(char* appx)
return xPlat::ResultOf([&]() {
xPlat::ComPtr<IStream> rawFile(new xPlat::FileStream(appx, xPlat::FileStream::Mode::READ));
{
xPlat::ZipObject zip(rawFile.Get());
APPX_VALIDATION_OPTION validationOption = APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_FULL;
std::function<LPVOID STDMETHODCALLTYPE(SIZE_T cb)> allocator=[](SIZE_T cb){return std::malloc(cb);};
std::function<void STDMETHODCALLTYPE(LPVOID pv)> deallocator=[](LPVOID pv){ std::free(pv);};
xPlat::ComPtr<IAppxFactory> factory;
ThrowHrIfFailed(CoCreateAppxFactoryWithHeap(InternalAllocate, InternalFree, validationOption, &factory));
auto internalFactory = factory.As<IxPlatFactory>();
xPlat::ZipObject zip(internalFactory.Get(), rawFile.Get());
auto p7xStream = zip.GetFile("AppxSignature.p7x");
std::vector<std::uint8_t> buffer(sizeof(_BLOBHEADER));
@ -216,8 +232,7 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE CreateStreamOnFile(
IStream** stream)
{
return xPlat::ResultOf([&]() {
xPlat::ComPtr<IStream> file(new xPlat::FileStream(utf8File, forRead ? xPlat::FileStream::Mode::READ : xPlat::FileStream::Mode::WRITE_UPDATE));
*stream = file.Get();
*stream = xPlat::ComPtr<IStream>(new xPlat::FileStream(utf8File, forRead ? xPlat::FileStream::Mode::READ : xPlat::FileStream::Mode::WRITE_UPDATE)).Detach();
});
}
@ -227,10 +242,9 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE CreateStreamOnFileUTF16(
IStream** stream)
{
return xPlat::ResultOf([&]() {
xPlat::ComPtr<IStream> file(new xPlat::FileStream(
*stream = xPlat::ComPtr<IStream>(new xPlat::FileStream(
xPlat::utf16_to_utf8(utf16File),
forRead ? xPlat::FileStream::Mode::READ : xPlat::FileStream::Mode::WRITE_UPDATE));
*stream = file.Get();
forRead ? xPlat::FileStream::Mode::READ : xPlat::FileStream::Mode::WRITE_UPDATE)).Detach();
});
}
@ -241,8 +255,7 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE CoCreateAppxFactoryWithHeap(
IAppxFactory** appxFactory)
{
return xPlat::ResultOf([&]() {
xPlat::ComPtr<IAppxFactory> result(new xPlat::AppxFactory(validationOption, memalloc, memfree));
*appxFactory = result.Get();
*appxFactory = xPlat::ComPtr<IAppxFactory>(new xPlat::AppxFactory(validationOption, memalloc, memfree)).Detach();
});
}
@ -254,8 +267,6 @@ XPLATAPPX_API HRESULT STDMETHODCALLTYPE CoCreateAppxFactory(
#ifdef WIN32
return CoCreateAppxFactoryWithHeap(CoTaskMemAlloc, CoTaskMemFree, validationOption, appxFactory);
#else
return static_cast<HRESULT>(xPlat::Error::NotSupported);
// We can't default to CoCreateAppxFactoryWithHeap(new, delete[], validationOption, AppxFactory);
// because we can't assume that the client is necessarily using the same heap as us!
return static_cast<HRESULT>(Error::NotSupported);
#endif
}