Merged PR 1206790: Merge feature to master

Bunch of bug fixes, and enable Linux and x64 Windows builds.

Related work items: #14874780, #14883294, #14942409, #14942463, #14986525, #14998095
This commit is contained in:
Phil Smith 2017-12-11 20:54:32 +00:00
Родитель 7aaee2fa2b 03d0425e0d
Коммит 009166a7cb
25 изменённых файлов: 612 добавлений и 115 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -397,4 +397,5 @@ __pycache__/
lib/zlib
# Files generated by CMake
src/inc/AppxCerts.hpp
src/inc/AppxBlockMapSchemas.hpp
src/inc/AppxBlockMapSchemas.hpp
src/inc/ContentTypesSchemas.hpp

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

@ -42,7 +42,7 @@
<xs:simpleType name="ST_ResourceReference">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
</xs:restriction>
</xs:simpleType>
@ -127,7 +127,7 @@
<xs:pattern value=".+\.([Dd][Ll][Ll])"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_ImageFile">
<xs:restriction base="ST_FileName">
<xs:pattern value=".+\.((jpg)|(png)|(jpeg))"/>
@ -306,7 +306,7 @@
<xs:enumeration value="x86a64"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_ArchitectureUnrestricted">
<xs:restriction base="ST_AsciiIdentifier">
<xs:maxLength value="7"/>
@ -547,7 +547,7 @@
<xs:enumeration value="windows.comInterface"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_PackageExtensionCategory_Foundation">
<xs:restriction base="xs:string">
<xs:enumeration value="windows.activatableClass.inProcessServer"/>

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

@ -206,7 +206,7 @@
<xs:element name="GameExplorer" type="CT_GameExplorer"/>
<!--Certificates DEH-->
<xs:element name="Certificates" type="CT_Certificates"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -274,7 +274,7 @@
<xs:selector xpath="m:Extensions/m:Extension/m:AutoPlayDevice/m:LaunchAction"/>
<xs:field xpath="@Verb"/>
</xs:unique>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here (Uniqueness checks)]
@@END_SDKSPLIT -->
</xs:element>
@ -286,7 +286,7 @@
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
<!-- VISUAL ELEMENTS SCHEMA -->
<xs:complexType name="CT_VisualElements">
<xs:all>
@ -403,7 +403,7 @@
<xs:element name="FileSavePicker" type="CT_FilePicker"/>
<!--Background Tasks DEH-->
<xs:element name="BackgroundTasks" type="CT_BackgroundTasks"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -471,14 +471,14 @@
<xs:simpleType name="ST_DisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,256}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_ShortDisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,40}"/>
</xs:restriction>
</xs:simpleType>
@ -606,7 +606,7 @@
</xs:restriction>
</xs:simpleType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
<!--DEPLOYMENT EXTENSION HANDLERS (DEH) SCHEMAS-->
@ -894,7 +894,7 @@
<xs:attribute name="GameDefinitionContainer" type="ST_FileName" use="required"/>
</xs:complexType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH schema here]
@@END_SDKSPLIT -->
</xs:schema>

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

@ -19,8 +19,8 @@
Please contact 'manifest' alias if you need to request an addition
or edit to the schema.
When modifying this file, please keep it consistent with the
When modifying this file, please keep it consistent with the
Schema\WindowsSDK\AppxManifestSchema2010_v2.xsd file
@@END_SDKSPLIT -->
@ -235,7 +235,7 @@
<xs:element name="ProxyStub" type="CT_ProxyStub"/>
<!--Certificates DEH-->
<xs:element name="Certificates" type="CT_Certificates"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -302,7 +302,7 @@
<xs:selector xpath="m:Extensions/m:Extension/m:AutoPlayDevice/m:LaunchAction"/>
<xs:field xpath="@Verb"/>
</xs:unique>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here (Uniqueness checks)]
@@END_SDKSPLIT -->
</xs:element>
@ -314,7 +314,7 @@
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
<!-- VISUAL ELEMENTS SCHEMA -->
<xs:attributeGroup name="VisualElementsBaseAttributes">
<xs:attribute name="DisplayName" type="ST_DisplayName" use="required"/>
@ -441,7 +441,7 @@
<xs:element name="FileSavePicker" type="CT_FilePicker"/>
<!--Background Tasks DEH-->
<xs:element name="BackgroundTasks" type="CT_BackgroundTasks"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -514,14 +514,14 @@
<xs:simpleType name="ST_DisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,256}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_ShortDisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,40}"/>
</xs:restriction>
</xs:simpleType>
@ -649,7 +649,7 @@
</xs:restriction>
</xs:simpleType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
<!--DEPLOYMENT EXTENSION HANDLERS (DEH) SCHEMAS-->
@ -938,7 +938,7 @@
</xs:restriction>
</xs:simpleType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH schema here]
@@END_SDKSPLIT -->
</xs:schema>

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

@ -242,7 +242,7 @@
<xs:element name="ProxyStub" type="CT_ProxyStub"/>
<!--Certificates DEH-->
<xs:element name="Certificates" type="CT_Certificates"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -313,7 +313,7 @@
<xs:selector xpath="m:Extensions/m:Extension/m:AutoPlayDevice/m:LaunchAction"/>
<xs:field xpath="@Verb"/>
</xs:unique>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here (Uniqueness checks)]
@@END_SDKSPLIT -->
</xs:element>
@ -325,7 +325,7 @@
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
<!-- VISUAL ELEMENTS SCHEMA -->
<xs:attributeGroup name="VisualElementsBaseAttributes">
<xs:attribute name="DisplayName" type="ST_DisplayName" use="required"/>
@ -452,7 +452,7 @@
<xs:element name="FileSavePicker" type="CT_FilePicker"/>
<!--Background Tasks DEH-->
<xs:element name="BackgroundTasks" type="CT_BackgroundTasks"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -525,14 +525,14 @@
<xs:simpleType name="ST_DisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,256}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_ShortDisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,40}"/>
</xs:restriction>
</xs:simpleType>
@ -660,7 +660,7 @@
</xs:restriction>
</xs:simpleType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
<!--DEPLOYMENT EXTENSION HANDLERS (DEH) SCHEMAS-->
@ -949,7 +949,7 @@
</xs:restriction>
</xs:simpleType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH schema here]
@@END_SDKSPLIT -->
</xs:schema>

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

@ -236,7 +236,7 @@
<xs:element name="ProxyStub" type="CT_ProxyStub"/>
<!--Certificates DEH-->
<xs:element name="Certificates" type="CT_Certificates"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -303,7 +303,7 @@
<xs:selector xpath="m:Extensions/m:Extension/m:AutoPlayDevice/m:LaunchAction"/>
<xs:field xpath="@Verb"/>
</xs:unique>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here (Uniqueness checks)]
@@END_SDKSPLIT -->
</xs:element>
@ -315,7 +315,7 @@
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
<!-- VISUAL ELEMENTS SCHEMA -->
<xs:attributeGroup name="VisualElementsBaseAttributes">
<xs:attribute name="DisplayName" type="ST_DisplayName" use="required"/>
@ -442,7 +442,7 @@
<xs:element name="FileSavePicker" type="CT_FilePicker"/>
<!--Background Tasks DEH-->
<xs:element name="BackgroundTasks" type="CT_BackgroundTasks"/>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
</xs:choice>
@ -515,14 +515,14 @@
<xs:simpleType name="ST_DisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,256}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_ShortDisplayName">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="\bms-resource:.{1,256}"/>
<xs:pattern value="ms-resource:.{1,256}"/>
<xs:pattern value=".{1,40}"/>
</xs:restriction>
</xs:simpleType>
@ -650,7 +650,7 @@
</xs:restriction>
</xs:simpleType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH here]
@@END_SDKSPLIT -->
<!--DEPLOYMENT EXTENSION HANDLERS (DEH) SCHEMAS-->
@ -939,7 +939,7 @@
</xs:restriction>
</xs:simpleType>
<!-- @@BEGIN_SDKSPLIT
<!-- @@BEGIN_SDKSPLIT
[Add your DEH schema here]
@@END_SDKSPLIT -->
</xs:schema>

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

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns="http://schemas.openxmlformats.org/package/2006/content-types" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://schemas.openxmlformats.org/package/2006/content-types" elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all">
<!--
Individual patterns for content type grammar
For better readability, each pattern using numbers is also described in a comment using
one of the following pattern designators.
-->
<!--DEFINE [media-type] "([type]/[subtype]([LWS]*;[LWS]*[parameter])*)" -->
<!--DEFINE [parameter] "([attribute]=[value])" -->
<!--DEFINE [attribute] "([token])" -->
<!--DEFINE [value] "([token]|[quoted-string])" -->
<!--DEFINE [subtype] "([token])" -->
<!--DEFINE [type] "([token])" -->
<!--DEFINE [quoted-string] "(&quot;([qdtext]|[quoted-pair])*&quot;)" -->
<!--DEFINE [qdtext] "([\p{IsLatin-1Supplement}\p{IsBasicLatin}-[\p{Cc}[DEL]&quot;\n\r]]|[LWS])" -->
<!--DEFINE [quoted-pair] "(\\[CHAR])" -->
<!--DEFINE [LWS] "([SP]+)" -->
<!--DEFINE [CHAR] "[\p{IsBasicLatin}]" -->
<!--DEFINE [separators] "[\(\)&lt;&gt;@,;:\\&quot;/\[\]\?=\{\} \t]" -->
<!--DEFINE [token] "(([\p{IsBasicLatin}-[\p{Cc}[DEL]\(\)&lt;&gt;@,;:\\&quot;/\[\]\?=\{\}\s\t]])+)" -->
<!--DEFINE [SP] "\s" -->
<!--DEFINE [DEL] "&#127;" -->
<xs:element name="Types" type="CT_Types" />
<xs:element name="Default" type="CT_Default" />
<xs:element name="Override" type="CT_Override" />
<xs:complexType name="CT_Types">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Default" />
<xs:element ref="Override" />
</xs:choice>
</xs:complexType>
<xs:complexType name="CT_Default">
<xs:attribute name="Extension" type="ST_Extension" use="required" />
<xs:attribute name="ContentType" type="ST_ContentType" use="required" />
</xs:complexType>
<xs:complexType name="CT_Override">
<xs:attribute name="ContentType" type="ST_ContentType" use="required" />
<xs:attribute name="PartName" type="xs:anyURI" use="required" />
</xs:complexType>
<xs:simpleType name="ST_ContentType">
<xs:restriction base="xs:string">
<!--
<xs:pattern value="[media-type]"/>
-->
<xs:pattern value="(((([\p{IsBasicLatin}-[\p{Cc}&#127;\(\)&lt;&gt;@,;:\\&quot;/\[\]\?=\{\}\s\t]])+))/((([\p{IsBasicLatin}-[\p{Cc}&#127;\(\)&lt;&gt;@,;:\\&quot;/\[\]\?=\{\}\s\t]])+))((\s+)*;(\s+)*(((([\p{IsBasicLatin}-[\p{Cc}&#127;\(\)&lt;&gt;@,;:\\&quot;/\[\]\?=\{\}\s\t]])+))=((([\p{IsBasicLatin}-[\p{Cc}&#127;\(\)&lt;&gt;@,;:\\&quot;/\[\]\?=\{\}\s\t]])+)|(&quot;(([\p{IsLatin-1Supplement}\p{IsBasicLatin}-[\p{Cc}&#127;&quot;\n\r]]|(\s+))|(\\[\p{IsBasicLatin}]))*&quot;))))*)" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_Extension">
<xs:restriction base="xs:string">
<xs:pattern value="([!$&amp;'\(\)\*\+,:=]|(%[0-9a-fA-F][0-9a-fA-F])|[:@]|[a-zA-Z0-9\-_~])+" />
</xs:restriction>
</xs:simpleType>
</xs:schema>

8
makewin32x64.cmd Normal file
Просмотреть файл

@ -0,0 +1,8 @@
REM HUZZA FOR: https://dmerej.info/blog/post/cmake-visual-studio-and-the-command-line/
if not exist .vs md .vs
cd .vs
if exist CMakeFiles rd /s /q CMakeFiles
if exist CMakeCache.txt del CMakeCache.txt
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
cmake -DWIN32=on -DCMAKE_BUILD_TYPE=Release -G"NMake Makefiles" ..
nmake

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

@ -3,6 +3,10 @@
#include <string>
#include <locale>
#include <codecvt>
#include <iostream>
#include <iomanip>
#include <functional>
#include <map>
#ifdef WIN32
#define UNICODE
@ -68,6 +72,98 @@ std::wstring utf8_to_utf16(const std::string& utf8string)
return result;
}
// describes an option to a command that the user may specify
struct Option
{
using CBF = std::function<bool(const std::string& value)>;
Option(bool param, const std::string& help, CBF callback): Help(help), Callback(callback), TakesParameter(param)
{}
bool TakesParameter;
std::string Name;
std::string Help;
CBF Callback;
};
// Tracks the state of the current parse operation as well as implements input validation
struct State
{
bool CreatePackageSubfolder()
{
unpackOptions = static_cast<APPX_PACKUNPACK_OPTION>(unpackOptions | APPX_PACKUNPACK_OPTION::APPX_PACKUNPACK_OPTION_CREATEPACKAGESUBFOLDER);
return true;
}
bool SkipManifestValidation()
{
validationOptions = static_cast<APPX_VALIDATION_OPTION>(validationOptions | APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_SKIPAPPXMANIFEST);
return true;
}
bool SkipSignature()
{
validationOptions = static_cast<APPX_VALIDATION_OPTION>(validationOptions | APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_SKIPSIGNATURE);
return true;
}
bool AllowSignatureOriginUnknown()
{
validationOptions = static_cast<APPX_VALIDATION_OPTION>(validationOptions | APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_ALLOWSIGNATUREORIGINUNKNOWN);
return true;
}
bool SetPackageName(const std::string& name)
{
if (!packageName.empty() || name.empty()) { return false; }
packageName = utf8_to_utf16(name);
return true;
}
bool SetDirectoryName(const std::string& name)
{
if (!directoryName.empty() || name.empty()) { return false; }
directoryName = utf8_to_utf16(name);
return true;
}
std::wstring packageName;
std::wstring directoryName;
APPX_VALIDATION_OPTION validationOptions = APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_FULL;
APPX_PACKUNPACK_OPTION unpackOptions = APPX_PACKUNPACK_OPTION::APPX_PACKUNPACK_OPTION_NONE;
};
// Displays contextual formatted help to the user.
int Help(char* toolName, std::map<std::string, Option>& options)
{
std::cout << std::endl;
std::cout << "Usage:" << std::endl;
std::cout << "------" << std::endl;
std::cout << "\t" << toolName << " -p <package> -d <directory> [options] " << std::endl;
std::cout << std::endl;
std::cout << "Description:" << std::endl;
std::cout << "------------" << std::endl;
std::cout << "\tExtracts all files within an app package at the input <package> name to the" << std::endl;
std::cout << "\tspecified output <directory>. The output has the same directory structure " << std::endl;
std::cout << "\tas the package." << std::endl;
std::cout << std::endl;
std::cout << "Options:" << std::endl;
std::cout << "--------" << std::endl;
for (const auto& option : options)
{
std::cout << "\t" << std::left << std::setfill(' ') << std::setw(5) <<
option.first << ": " << option.second.Help << std::endl;
}
return 0;
}
// error text if the user provided underspecified input
void Error(char* toolName)
{
std::cout << toolName << ": error : Missing required options. Use '-?' for more details." << std::endl;
}
#ifdef WIN32
// TODO: paths coming in SHOULD have platform-appropriate path separators
void replace(std::wstring& input, const wchar_t oldchar, const wchar_t newchar)
@ -147,7 +243,7 @@ struct FootprintFilesType
// Types of footprint files in an app package
const int FootprintFilesCount = 4;
const FootprintFilesType footprintFilesType[FootprintFilesCount] = {
FootprintFilesType footprintFilesType[FootprintFilesCount] = {
{APPX_FOOTPRINT_FILE_TYPE_MANIFEST, "manifest", true },
{APPX_FOOTPRINT_FILE_TYPE_BLOCKMAP, "block map", true },
{APPX_FOOTPRINT_FILE_TYPE_SIGNATURE, "digital signature", true },
@ -198,13 +294,13 @@ void STDMETHODCALLTYPE MyFree(LPVOID pv) { std::free(pv); }
// reader
// On success, receives the created instance of IAppxPackageReader.
//
HRESULT GetPackageReader(LPCWSTR inputFileName, IAppxPackageReader** package)
HRESULT GetPackageReader(State& state, IAppxPackageReader** package)
{
HRESULT hr = S_OK;
ComPtr<IAppxFactory> appxFactory;
ComPtr<IStream> inputStream;
hr = CreateStreamOnFileUTF16(inputFileName, true, &inputStream);
hr = CreateStreamOnFileUTF16(state.packageName.c_str(), true, &inputStream);
if (SUCCEEDED(hr))
{
// On Win32 platforms CoCreateAppxFactory defaults to CoTaskMemAlloc/CoTaskMemFree
@ -213,7 +309,7 @@ HRESULT GetPackageReader(LPCWSTR inputFileName, IAppxPackageReader** package)
hr = CoCreateAppxFactoryWithHeap(
MyAllocate,
MyFree,
APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_SKIPAPPXMANIFEST,
state.validationOptions,
&appxFactory);
// Create a new package reader using the factory. For
@ -361,33 +457,88 @@ HRESULT ExtractPayloadFiles(IAppxPackageReader* package, LPCWSTR outputPath)
return hr;
}
int main(int argc, char* argv[])
// Parses argc/argv input via commands into state, and extract the package.
int ParseAndRun(std::map<std::string, Option>& options, State& state, int argc, char* argv[])
{
HRESULT hr = S_OK;
auto ParseInput = [&]()->bool {
int index = 1;
while (index < argc)
{
auto option = options.find(argv[index]);
if (option == options.end()) { return false; }
char const *parameter = "";
if (option->second.TakesParameter)
{
if (++index == argc) { break; }
parameter = argv[index];
}
if (!option->second.Callback(parameter)) { return false; }
++index;
}
return true;
};
std::wstring fileName = utf8_to_utf16(argv[1]);
std::wstring pathName = utf8_to_utf16(argv[2]);
if (!ParseInput()) { return Help(argv[0], options); }
if (state.packageName.empty() || state.directoryName.empty())
{ Error(argv[0]);
return -1;
}
HRESULT hr = S_OK;
// Create a package using the file name in argv[1]
ComPtr<IAppxPackageReader> package;
hr = GetPackageReader(fileName.c_str(), &package);
hr = GetPackageReader(state, &package);
// Print information about all footprint files, and extract them to disk
if (SUCCEEDED(hr))
{
hr = ExtractFootprintFiles(package.Get(), pathName.c_str());
hr = ExtractFootprintFiles(package.Get(), state.directoryName.c_str());
}
// Print information about all payload files, and extract them to disk
if (SUCCEEDED(hr))
{
hr = ExtractPayloadFiles(package.Get(), pathName.c_str());
hr = ExtractPayloadFiles(package.Get(), state.directoryName.c_str());
}
if (FAILED(hr))
{
// TODO: Tell a more specific reason why the faiulre occurred.
std::printf("\nError %X occurred while extracting the appx package\n", static_cast<int>(hr));
}
return static_cast<int>(hr);
}
int main(int argc, char* argv[])
{
HRESULT hr = S_OK;
State state;
std::map<std::string, Option> options = {
{ "-p", Option(true, "REQUIRED, specify input package name.",
[&](const std::string& name) { return state.SetPackageName(name); })
},
{ "-d", Option(true, "REQUIRED, specify output directory name.",
[&](const std::string& name) { return state.SetDirectoryName(name); })
},
{ "-pfn", Option(false, "Unpacks all files to a subdirectory under the specified output path, named after the package full name.",
[&](const std::string&) { return state.CreatePackageSubfolder(); })
},
{ "-mv", Option(false, "Skips manifest validation. By default manifest validation is enabled.",
[&](const std::string&) { return state.SkipManifestValidation(); })
},
{ "-sv", Option(false, "Skips signature validation. By default signature validation is enabled.",
[&](const std::string&) { return state.AllowSignatureOriginUnknown(); })
},
{ "-ss", Option(false, "Skips enforcement of signed packages. By default packages must be signed.",
[&](const std::string&)
{ footprintFilesType[2].isRequired = false;
return state.SkipSignature();
})
},
{ "-?", Option(false, "Displays this help text.",
[&](const std::string&) { return false; })
}
};
auto result = ParseAndRun(options, state, argc, argv);
if (result != 0)
{
std::cout << "Error: " << std::hex << result << " while extracting the appx package" <<std::endl;
}
return result;
}

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

@ -7,6 +7,7 @@
#include "HashStream.hpp"
#include "ComHelper.hpp"
#include "SHA256.hpp"
#include "AppxFactory.hpp"
#include <string>
#include <map>
@ -35,7 +36,8 @@ namespace xPlat {
class BlockMapStream : public StreamBase
{
public:
BlockMapStream(IStream* stream, std::vector<Block>& blocks) : m_stream(stream)
BlockMapStream(IxPlatFactory* factory, std::string decodedName, IStream* stream, std::vector<Block>& blocks)
: m_factory(factory), m_decodedName(decodedName), m_stream(stream)
{
// Determine overall stream size
ULARGE_INTEGER uli;
@ -141,7 +143,7 @@ namespace xPlat {
HRESULT STDMETHODCALLTYPE GetName(LPWSTR* fileName) override
{
return ResultOf([&]{ return m_stream.As<IAppxFile>()->GetName(fileName); });
return m_factory->MarshalOutString(m_decodedName, fileName);
}
HRESULT STDMETHODCALLTYPE GetContentType(LPWSTR* contentType) override
@ -159,6 +161,8 @@ namespace xPlat {
std::vector<BlockPlusStream> m_blockStreams;
std::uint64_t m_relativePosition;
std::uint64_t m_streamSize;
std::string m_decodedName;
ComPtr<IStream> m_stream;
IxPlatFactory* m_factory;
};
}

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

@ -9,12 +9,12 @@
namespace xPlat {
// This represents a subset of a Stream
class RangeStream : public StreamBase
{
public:
RangeStream(std::uint64_t offset, std::uint64_t size, IStream* stream) :
RangeStream(std::uint64_t offset, std::uint64_t size, IStream* stream) :
m_offset(offset),
m_size(size),
m_stream(stream)
@ -40,7 +40,7 @@ namespace xPlat {
//TODO: We need to constrain newPos so that it can't exceed the end of the stream
ULARGE_INTEGER pos = { 0 };
m_stream->Seek(newPos, Reference::START, &pos);
m_relativePosition = std::min((pos.QuadPart - m_offset), m_size);
m_relativePosition = std::min(static_cast<std::uint64_t>(pos.QuadPart - m_offset), m_size);
if (newPosition) { newPosition->QuadPart = m_relativePosition; }
});
}

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

@ -27,7 +27,8 @@ namespace xPlat {
/*in*/ APPX_VALIDATION_OPTION option,
/*in*/ IStream *stream,
/*inout*/ std::map<xPlat::AppxSignatureObject::DigestName, xPlat::AppxSignatureObject::Digest>& digests,
/*inout*/ SignatureOrigin& origin);
/*inout*/ SignatureOrigin& origin,
/*inout*/ std::string& publisher);
};
}

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

@ -40,7 +40,7 @@ namespace xPlat {
bool hasValue = !attributeValue.empty();
std::uint32_t value = 0;
if (hasValue) { value = static_cast<std::uint32_t>(std::stoul(attributeValue)); }
return value;
return value;
}
static std::string GetName(XERCES_CPP_NAMESPACE::DOMElement* element)
@ -67,7 +67,7 @@ namespace xPlat {
XercesXMLChPtr nameAttr(XMLString::transcode("Hash"));
XMLSize_t len = 0;
XercesXMLBytePtr decodedData(XERCES_CPP_NAMESPACE::Base64::decodeToXMLByte(
element->getAttribute(nameAttr.Get()),
element->getAttribute(nameAttr.Get()),
&len));
std::vector<std::uint8_t> result(len);
for(XMLSize_t index=0; index < len; index++)
@ -83,7 +83,7 @@ namespace xPlat {
result.hash = GetDigestData(element);
return result;
}
AppxBlockMapObject::AppxBlockMapObject(IxPlatFactory* factory, ComPtr<IStream>& stream) : m_factory(factory), m_stream(stream)
{
auto dom = ComPtr<IXmlObject>::Make<XmlObject>(stream, &blockMapSchema);
@ -103,8 +103,13 @@ namespace xPlat {
fileResult->snapshotItem(i);
auto fileNode = static_cast<DOMElement*>(fileResult->getNodeValue());
auto name = GetName(fileNode);
ThrowErrorIf(Error::BlockMapSemanticError, (name == "[Content_Types].xml"), "[Content_Types].xml cannot be in the AppxBlockMap.xml file");
auto existing = m_blockMap.find(name);
ThrowErrorIf(Error::BlockMapSemanticError, (existing != m_blockMap.end()), "duplicate file name specified.");
// Get blocks elements
XercesXMLChPtr blockXPath(XMLString::transcode("./Block"));
XercesXMLChPtr blockXPath(XMLString::transcode("./Block"));
XercesPtr<DOMXPathResult> blockResult = dom->Document()->evaluate(
blockXPath.Get(),
fileNode,
@ -113,19 +118,15 @@ namespace xPlat {
nullptr);
// get all the blocks for the file.
std::vector<Block> blocks(blockResult->getSnapshotLength());
std::vector<Block> blocks(blockResult->getSnapshotLength());
for (XMLSize_t j = 0; j < blockResult->getSnapshotLength(); j++)
{
blockResult->snapshotItem(j);
auto blockNode = static_cast<DOMElement*>(blockResult->getNodeValue());
blocks[j] = GetBlock(blockNode);
}
}
auto name = GetName(fileNode);
auto existing = m_blockMap.find(name);
ThrowErrorIf(Error::BlockMapSemanticError, (existing != m_blockMap.end()), "duplicate file name specified.");
m_blockMap.insert(std::make_pair(name, std::move(blocks)));
m_blockMapfiles.insert(std::make_pair(name,
ComPtr<IAppxBlockMapFile>::Make<AppxBlockMapFile>(
factory,
@ -133,7 +134,7 @@ namespace xPlat {
GetLocalFileHeaderSize(fileNode),
name,
GetSize(fileNode))));
}
}
}
xPlat::ComPtr<IStream> AppxBlockMapObject::GetValidationStream(const std::string& part, IStream* stream)
@ -141,7 +142,7 @@ namespace xPlat {
ThrowErrorIf(Error::InvalidParameter, (part.empty() || stream == nullptr), "bad input");
auto item = m_blockMap.find(part);
ThrowErrorIf(Error::BlockMapSemanticError, item == m_blockMap.end(), "file not tracked by blockmap");
return ComPtr<IStream>::Make<BlockMapStream>(stream, item->second);
return ComPtr<IStream>::Make<BlockMapStream>(m_factory, part, stream, item->second);
}
HRESULT STDMETHODCALLTYPE AppxBlockMapObject::GetFile(LPCWSTR filename, IAppxBlockMapFile **file)
@ -162,7 +163,7 @@ namespace xPlat {
ComPtr<IAppxBlockMapReader> self;
ThrowHrIfFailed(QueryInterface(UuidOfImpl<IAppxBlockMapReader>::iid, reinterpret_cast<void**>(&self)));
*enumerator = ComPtr<IAppxBlockMapFilesEnumerator>::Make<AppxBlockMapFilesEnumerator>(
self.Get(),
self.Get(),
std::move(GetFileNames(FileNameOptions::All))).Detach();
});
}

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

@ -5,6 +5,7 @@
#include "StorageObject.hpp"
#include "AppxPackageObject.hpp"
#include "UnicodeConversion.hpp"
#include "ContentTypesSchemas.hpp"
#include <string>
#include <vector>
@ -31,8 +32,8 @@ namespace xPlat {
};
static const std::uint8_t PercentangeEncodingTableSize = 0x5E;
static const std::vector<std::string> PercentangeEncoding = {
"", "", "", "", "", "", "", "",
static const std::vector<std::string> PercentangeEncoding =
{ "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
@ -47,8 +48,7 @@ namespace xPlat {
};
static const std::map<std::string, char> EncodingToChar =
{
{"20", ' '}, {"21", '!'}, {"23", '#'}, {"24", '$'},
{ {"20", ' '}, {"21", '!'}, {"23", '#'}, {"24", '$'},
{"25", '%'}, {"26", '&'}, {"27", '\''}, {"28", '('},
{"29", ')'}, {"25", '+'}, {"2B", '%'}, {"2C", ','},
{"3B", ';'}, {"3D", '='}, {"40", '@'}, {"5B", '['},
@ -59,19 +59,15 @@ namespace xPlat {
{
std::string result;
for (std::uint32_t position = 0; position < fileName.length(); ++position)
{
std::uint8_t index = static_cast<std::uint8_t>(fileName[position]);
{ std::uint8_t index = static_cast<std::uint8_t>(fileName[position]);
if(fileName[position] < PercentangeEncodingTableSize && index < PercentangeEncoding.size() && !PercentangeEncoding[index].empty())
{
result += PercentangeEncoding[index];
{ result += PercentangeEncoding[index];
}
else if (fileName[position] == '\\') // Remove Windows file name
{
result += '/';
else if (fileName[position] == '\\') // Remove Windows file separator.
{ result += '/';
}
else
{
result += fileName[position];
{ result += fileName[position];
}
}
return result;
@ -81,27 +77,18 @@ namespace xPlat {
{
std::string result;
for (std::uint32_t i = 0; i < fileName.length(); ++i)
{
if(fileName[i] == '%')
{
auto found = EncodingToChar.find(fileName.substr(i+1, 2));
{ if(fileName[i] == '%')
{ auto found = EncodingToChar.find(fileName.substr(i+1, 2));
if (found != EncodingToChar.end())
{
result += found->second;
{ result += found->second;
}
else
{
throw Exception(Error::AppxUnknownFileNameEncoding, fileName);
{ throw Exception(Error::AppxUnknownFileNameEncoding, fileName);
}
i += 2;
}
else if (fileName[i] == '/') // Windows file name
{
result += '\\';
}
else
{
result += fileName[i];
{ result += fileName[i];
}
}
return result;
@ -141,7 +128,7 @@ namespace xPlat {
// 2. Get content type using signature object for validation
// TODO: switch underlying type of m_contentType to something more specific.
auto temp = m_appxSignature->GetValidationStream(CONTENT_TYPES_XML, m_container->GetFile(CONTENT_TYPES_XML));
m_contentType = ComPtr<IVerifierObject>::Make<XmlObject>(temp);
m_contentType = ComPtr<IVerifierObject>::Make<XmlObject>(temp, &contentTypesSchema);
ThrowErrorIfNot(Error::AppxMissingContentTypesXML, (m_contentType->HasStream()), "[Content_Types].xml not in archive!");
// 3. Get blockmap object using signature object for validation
@ -210,13 +197,11 @@ namespace xPlat {
{
std::string targetName;
if (options & APPX_PACKUNPACK_OPTION_CREATEPACKAGESUBFOLDER)
{
throw Exception(Error::NotImplemented);
{ throw Exception(Error::NotImplemented);
//targetName = GetAppxManifest()->GetPackageFullName() + to->GetPathSeparator() + fileName;
}
else
{
targetName = fileName;
{ targetName = DecodeFileName(fileName);
}
auto targetFile = to->OpenFile(targetName, xPlat::FileStream::Mode::WRITE_UPDATE);

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

@ -21,7 +21,8 @@ AppxSignatureObject::AppxSignatureObject(APPX_VALIDATION_OPTION validationOption
m_stream(stream),
m_validationOptions(validationOptions)
{
m_hasDigests = SignatureValidator::Validate(validationOptions, stream, m_digests, m_signatureOrigin);
std::string publisher;
m_hasDigests = SignatureValidator::Validate(validationOptions, stream, m_digests, m_signatureOrigin, publisher);
if (0 == (validationOptions & APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_SKIPSIGNATURE))
{ // reset the source stream back to the beginning after validating it.

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

@ -52,6 +52,17 @@ std::map<std::string, std::string> blockMapSchema = {
")
file(WRITE "../inc/AppxBlockMapSchemas.hpp" "${BLOCKMAP_HEADER}")
# Create header for [Content_Types] schema
file(READ "${CMAKE_PROJECT_ROOT}/AppxPackaging/[Content_Types]/opc-contentTypes.xsd" CONTENT_TYPES_SCHEMA)
set(CONTENT_TYPES_HEADER "// This file is generated by CMake and contains XSDs for parsing [Content_Types].xml. Do not edit!!
#include <string>
#include <map>
std::map<std::string, std::string> contentTypesSchema = {
{\"contentTypesSchemaRaw\", R\"###(${CONTENT_TYPES_SCHEMA})###\" }
};
")
file(WRITE "../inc/ContentTypesSchemas.hpp" "${CONTENT_TYPES_HEADER}")
set(LIB_PUBLIC_HEADERS
../inc/AppxPackaging.hpp
../inc/AppxWindows.hpp

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

@ -40,8 +40,8 @@ namespace xPlat
void operator()(X509_STORE_CTX *xsc) const { if (xsc) {X509_STORE_CTX_cleanup(xsc); X509_STORE_CTX_free(xsc);} };
};
struct unique_X509_NAME_deleter {
void operator()(X509_NAME *xn) const { if (xn) OPENSSL_free(xn); };
struct unique_OPENSSL_string_deleter {
void operator()(char *os) const { if (os) OPENSSL_free(os); };
};
struct unique_STACK_X509_deleter {
@ -57,9 +57,9 @@ namespace xPlat
typedef std::unique_ptr<X509, unique_X509_deleter> unique_X509;
typedef std::unique_ptr<X509_STORE, unique_X509_STORE_deleter> unique_X509_STORE;
typedef std::unique_ptr<X509_STORE_CTX, unique_X509_STORE_CTX_deleter> unique_X509_STORE_CTX;
typedef std::unique_ptr<X509_NAME, unique_X509_NAME_deleter> unique_X509_NAME;
typedef std::unique_ptr<char, unique_OPENSSL_string_deleter> unique_OPENSSL_string;
typedef std::unique_ptr<STACK_OF(X509), unique_STACK_X509_deleter> unique_STACK_X509;
typedef struct Asn1Sequence
{
std::uint8_t tag;
@ -239,11 +239,76 @@ namespace xPlat
return ok;
}
bool GetPublisherName(/*in*/ unique_PKCS7& p7, /*inout*/ std::string& publisher)
{
X509* cert = nullptr;
STACK_OF(X509) *untrustedCerts = p7.get()->d.sign->cert;
// If there's only one cert, it's a self-signed package; just return its subject
if (sk_X509_num(untrustedCerts) == 1)
{
cert = sk_X509_value(untrustedCerts, 0);
}
else
{
std::map<std::string/*issuer*/, int/*refcount*/> issuers;
for (int i = 0; i < sk_X509_num(untrustedCerts); i++)
{
X509* certT = sk_X509_value(untrustedCerts, i);
unique_OPENSSL_string issuer(X509_NAME_oneline(X509_get_issuer_name(certT), NULL, 0));
auto search = issuers.find(issuer.get());
// If the issuer is not in the map, add it and set refcount to 1
if (search == issuers.end())
{
issuers[issuer.get()] = 1;
}
else
{
// This issuer is in the map, increment its refcount
int count = search->second;
issuers[issuer.get()] = count + 1;
}
}
// Now, loop through the certs and find out which one isn't an issuer
for (int i = 0; i < sk_X509_num(untrustedCerts); i++)
{
X509* certT = sk_X509_value(untrustedCerts, i);
unique_OPENSSL_string subject(X509_NAME_oneline(X509_get_subject_name(certT), NULL, 0));
auto search = issuers.find(subject.get());
// If the subject is not in the map, we have found our cert
if (search == issuers.end())
{
cert = certT;
break;
}
}
}
// We should have found a certificate
if (cert)
{
// Create a BIO memory buffer, and print the subject name to it.
unique_BIO bio(BIO_new(BIO_s_mem()));
X509_NAME_print_ex(bio.get(),
X509_get_subject_name(cert),
0,
XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV);
// Now extract the publisher from the BIO print buffer
char *memBuffer = nullptr;
BIO_get_mem_data(bio.get(), &memBuffer);
publisher = std::string(memBuffer);
return true;
}
return false;
}
bool SignatureValidator::Validate(
/*in*/ APPX_VALIDATION_OPTION option,
/*in*/ IStream *stream,
/*inout*/ std::map<xPlat::AppxSignatureObject::DigestName, xPlat::AppxSignatureObject::Digest>& digests,
/*inout*/ SignatureOrigin& origin)
/*inout*/ SignatureOrigin& origin,
/*inout*/ std::string& publisher)
{
// If the caller wants to skip signature validation altogether, just bug out early. We will not read the digests
if (option & APPX_VALIDATION_OPTION_SKIPSIGNATURE) { return false; }
@ -337,6 +402,11 @@ namespace xPlat
xPlat::SignatureOrigin::LOB == origin ||
(option & APPX_VALIDATION_OPTION::APPX_VALIDATION_OPTION_ALLOWSIGNATUREORIGINUNKNOWN)
), "Signature origin check failed");
ThrowErrorIfNot(Error::AppxSignatureInvalid, (
GetPublisherName(p7, publisher) == true
), "Signature origin check failed");
return true;
}
} // namespace xPlat

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

@ -351,11 +351,40 @@ namespace xPlat
return IsAuthenticodeTrustedChain(certChainContext.get());
}
static bool GetPublisherName(/*in*/byte* signatureBuffer, /*in*/ ULONG cbSignatureBuffer, /*inout*/ std::string& publisher)
{
unique_cert_context certificateContext(GetCertContext(signatureBuffer, cbSignatureBuffer));
int requiredLength = CertNameToStrA(
X509_ASN_ENCODING,
&certificateContext.get()->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
nullptr,
0);
std::vector<char> publisherT;
publisherT.reserve(requiredLength + 1);
if (CertNameToStrA(
X509_ASN_ENCODING,
&certificateContext.get()->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
publisherT.data(),
requiredLength) > 0)
{
publisher = std::string(publisherT.data());
return true;
}
return false;
}
bool SignatureValidator::Validate(
/*in*/ APPX_VALIDATION_OPTION option,
/*in*/ IStream *stream,
/*inout*/ std::map<xPlat::AppxSignatureObject::DigestName, xPlat::AppxSignatureObject::Digest>& digests,
/*inout*/ SignatureOrigin& origin)
/*inout*/ SignatureOrigin& origin,
/*inout*/ std::string& publisher)
{
// If the caller wants to skip signature validation altogether, just bug out early. We will not read the digests
if (option & APPX_VALIDATION_OPTION_SKIPSIGNATURE) { return false; }
@ -518,6 +547,10 @@ namespace xPlat
((xPlat::SignatureOrigin::Unknown == origin) && !SignatureOriginUnknownAllowed),
"Unknown signature origin");
ThrowErrorIfNot(Error::AppxSignatureInvalid,
GetPublisherName(p7s, p7sSize, publisher) == true,
"Could not retrieve publisher name");
return true;
}
} // namespace xPlat

77
test/MacOS-Linux-Etc.sh Executable file
Просмотреть файл

@ -0,0 +1,77 @@
#!/bin/bash
TESTFAILED=0
function FindBinFolder {
#look in .vs/bin first
if [ -e "../.vs/bin/MakeXplat" ]
then
BINDIR="../.vs/bin"
elif [ -e "../.vscode/bin/MakeXplat" ]
then
BINDIR="../.vscode/bin"
elif [ -e "../build/bin/MakeXplat" ]
then
BINDIR="../build/bin"
else
echo "ERROR: Could not find build binaries"
exit
fi
}
function CleanupUnpackFolder {
rm -f -r ./unpack/*
if [ -e "./unpack/*" ]
then
echo "ERROR: Could not cleanup ./unpack directory"
exit
fi
}
function RunTest {
CleanupUnpackFolder
local SUCCESS="$1"
local UNPACKFOLDER="$2"
local ARGS="$3"
echo "------------------------------------------------------"
echo $BINDIR/MakeXplat unpack -d ./unpack -p $UNPACKFOLDER $ARGS
echo "------------------------------------------------------"
$BINDIR/MakeXplat unpack -d ./unpack -p $UNPACKFOLDER $ARGS
local RESULT=$?
echo "expect: "$SUCCESS", got: "$RESULT
if [ $RESULT -eq $SUCCESS ]
then
echo "succeeded"
else
echo "FAILED"
TESTFAILED=1
fi
}
FindBinFolder
# return code is last two digits, but in decimal, not hex. e.g. 0x8bad0002 == 2, 0x8bad0041 == 65, etc...
# common codes:
# AppxSignatureInvalid = ERROR_FACILITY + 0x0041 == 65
RunTest 2 ./appx/Empty.appx -sv
RunTest 0 ./appx/HelloWorld.appx -ss
RunTest 65 ./appx/SignatureNotLastPart-ERROR_BAD_FORMAT.appx
#RunTest 0x134 ./appx/SignedMismatchedPublisherName-ERROR_BAD_FORMAT.appx
RunTest 65 ./appx/SignedTamperedBlockMap-TRUST_E_BAD_DIGEST.appx
RunTest 65 ./appx/SignedTamperedBlockMap-TRUST_E_BAD_DIGEST.appx -sv
RunTest 65 ./appx/SignedTamperedCD-TRUST_E_BAD_DIGEST.appx
RunTest 65 ./appx/SignedTamperedCodeIntegrity-TRUST_E_BAD_DIGEST.appx
RunTest 65 ./appx/SignedTamperedContentTypes-TRUST_E_BAD_DIGEST.appx
RunTest 65 ./appx/SignedUntrustedCert-CERT_E_CHAINING.appx
RunTest 0 ./appx/StoreSigned_Desktop_x64_MoviesTV.appx
RunTest 65 ./appx/TestAppxPackage_Win32.appx
RunTest 65 ./appx/TestAppxPackage_x64.appx
RunTest 18 ./appx/UnsignedZip64WithCI-APPX_E_MISSING_REQUIRED_FILE.appx
echo "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
if [ $TESTFAILED -ne 0 ]
then
echo " FAILED "
exit $TESTFAILED
else
echo " passed "
exit 0
fi

94
test/Win32.ps1 Normal file
Просмотреть файл

@ -0,0 +1,94 @@
$global:TESTFAILED=0
$global:BINDIR=""
function FindBinFolder {
if (Test-Path "..\.vs\bin\MakeXplat.exe" )
{
$global:BINDIR="..\.vs\bin"
}
elseif (Test-Path "..\.vscode\bin\MakeXplat.exe" )
{
$global:BINDIR="..\.vscode\bin"
}
elseif (Test-Path "..\build\bin\MakeXplat.exe")
{
$global:BINDIR="..\build\bin"
}
else
{
write-host "ERROR: Could not find build binaries"
exit
}
}
function CleanupUnpackFolder {
Remove-Item ".\unpack\*" -recurse
if (Test-Path ".\unpack\*" )
{
write-host "ERROR: Could not cleanup .\unpack directory"
exit
}
}
function RunTest([string] $UNPACKFOLDER, [int] $SUCCESSCODE) {
CleanupUnpackFolder
write-host "------------------------------------------------------"
write-host $UNPACKFOLDER >> Win32.log
#$BINDIR\MakeXplat unpack -d .\unpack -p $UNPACKFOLDER
Start-Process "$BINDIR\MakeXplat.exe" -ArgumentList ("unpack", "-d", ".\unpack", "-p", $UNPACKFOLDER) -Wait
$ERRORCODE=$?
if ( $ERRORCODE -eq $SUCCESSCODE )
{
write-host "Succeeded: $SUCCESSCODE"
}
else
{
write-host "Expected: $SUCCESSCODE"
write-host "Failed: $ERRORCODE"
$global:TESTFAILED=1
}
}
FindBinFolder
RunTest .\appx\CentennialCoffee.appx 134
RunTest .\appx\Empty.appx 134
RunTest .\appx\HelloWorld.appx 134
RunTest .\appx\SignatureNotLastPart-ERROR_BAD_FORMAT.appx 134
RunTest .\appx\SignedMismatchedPublisherName-ERROR_BAD_FORMAT.appx 134
RunTest .\appx\SignedTamperedBlockMap-TRUST_E_BAD_DIGEST.appx 134
RunTest .\appx\SignedTamperedCD-TRUST_E_BAD_DIGEST.appx 134
RunTest .\appx\SignedTamperedCodeIntegrity-TRUST_E_BAD_DIGEST.appx 134
RunTest .\appx\SignedTamperedContentTypes-TRUST_E_BAD_DIGEST.appx 134
RunTest .\appx\SignedUntrustedCert-CERT_E_CHAINING.appx 134
RunTest .\appx\StoreSigned_Desktop_x64_MoviesTV.appx 0
RunTest .\appx\TestAppxPackage_Win32.appx 134
RunTest .\appx\TestAppxPackage_x64.appx 134
RunTest .\appx\UnsignedZip64WithCI-APPX_E_MISSING_REQUIRED_FILE.appx 134
RunTest .\appx\BlockMap\TODAVIANO\Signature_in_BlockMap.appx 134
RunTest .\appx\BlockMap\TODAVIANO\SignedTamperedBlockMap-TRUST_E_BAD_DIGEST.appx 134
RunTest .\appx\BlockMap\Missing_Manifest_in_blockmap.appx 134
RunTest .\appx\BlockMap\ContentTypes_in_blockmap.appx 134
RunTest .\appx\BlockMap\Invalid_Bad_Block.appx 134
RunTest .\appx\BlockMap\Size_wrong_uncompressed.appx 134
RunTest .\appx\BlockMap\HelloWorld.appx 134
RunTest .\appx\BlockMap\Extra_file_in_blockmap.appx 134
RunTest .\appx\BlockMap\File_missing_from_blockmap.appx 134
RunTest .\appx\BlockMap\No_blockmap.appx 134
RunTest .\appx\BlockMap\Bad_Namespace_Blockmap.appx 134
RunTest .\appx\BlockMap\Duplicate_file_in_blockmap.appx 134
CleanupUnpackFolder
if ( $global:TESTFAILED -eq 1 )
{
exit 134
}
else
{
exit 0
}

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
test/appx/InvalidSignatureBadCodeIntegrity.appx Normal file

Двоичный файл не отображается.

Двоичные данные
test/appx/InvalidSignatureInvalidCodeIntegrityXML.appx Normal file

Двоичный файл не отображается.

Двоичные данные
test/appx/OPC_E_ZIP_CORRUPTED_ARCHIVE.appx Normal file

Двоичный файл не отображается.