Merged PR 1609222: Unpack appx bundles

In this change:
- Enable unpacking appx bundles and recursive unpacking of the packages in the bundle.
- Generate PublsiherId using the Windows implementation
- Take out the bundles xsds from the RESOURCES_APPXBUNDLEMANIFEST set
- Remove cache semantics in DirectoryObject to avoid errono = 24 (too many files open) while unpacking a bundle
- Add appx bundle packages for testing
- Enable some tests on non-mobile platforms. On non-mobile we use the public APIs. This functionality will be enable in another PR.
This commit is contained in:
Ruben Guerrero Samaniego 2018-04-02 22:16:41 +00:00 коммит произвёл msftrubengu
Родитель bf2e8560d0
Коммит 41b3df6e61
49 изменённых файлов: 394 добавлений и 150 удалений

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

@ -10,7 +10,7 @@ xcuserdata/
*.xccheckout
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
build*/
DerivedData/
*.moved-aside
*.pbxuser

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

@ -8,6 +8,7 @@ set(RESOURCES_CERTS)
set(RESOURCES_BLOCKMAP)
set(RESOURCES_CONTENTTYPE)
set(RESOURCES_APPXMANIFEST)
set(RESOURCES_APPXBUNDLEMANIFEST)
if(NOT WIN32) # Always add the certs for non-Windows.
list(APPEND RESOURCES_CERTS
@ -34,8 +35,6 @@ if(HAVE_MSXML6)
list(APPEND RESOURCES_APPXMANIFEST
"AppxPackaging/Manifest/Schema/2015/AppxManifestTypes.xsd"
"AppxPackaging/Manifest/Schema/2015/AppxPhoneManifestSchema2014.xsd"
"AppxPackaging/Manifest/Schema/2015/BundleManifestSchema2013.xsd"
"AppxPackaging/Manifest/Schema/2015/BundleManifestSchema2014.xsd"
"AppxPackaging/Manifest/Schema/2015/ComManifestSchema.xsd"
"AppxPackaging/Manifest/Schema/2015/DesktopManifestSchema.xsd"
"AppxPackaging/Manifest/Schema/2015/FoundationManifestSchema.xsd"
@ -52,12 +51,10 @@ if(HAVE_MSXML6)
"AppxPackaging/Manifest/Schema/2015/WindowsCapabilitiesManifestSchema.xsd"
"AppxPackaging/Manifest/Schema/2015/WindowsCapabilitiesManifestSchema_v2.xsd"
"AppxPackaging/Manifest/Schema/2015/XboxManifestSchema.xsd"
"AppxPackaging/Manifest/Schema/2016/BundleManifestSchema2016.xsd"
"AppxPackaging/Manifest/Schema/2016/DesktopManifestSchema_v2.xsd"
"AppxPackaging/Manifest/Schema/2016/RestrictedCapabilitiesManifestSchema_v3.xsd"
"AppxPackaging/Manifest/Schema/2016/UapManifestSchema_v4.xsd"
"AppxPackaging/Manifest/Schema/2016/WindowsCapabilitiesManifestSchema_v3.xsd"
"AppxPackaging/Manifest/Schema/2017/BundleManifestSchema2017.xsd"
"AppxPackaging/Manifest/Schema/2017/ComManifestSchema_v2.xsd"
"AppxPackaging/Manifest/Schema/2017/DesktopManifestSchema_v3.xsd"
"AppxPackaging/Manifest/Schema/2017/DesktopManifestSchema_v4.xsd"
@ -69,16 +66,22 @@ else() # xerces
# TODO: make changes required to make the xsds WC3 compliant.
endif()
endif(USE_VALIDATION_PARSER)
list(APPEND RESOURCES_APPXBUNDLEMANIFEST
"AppxPackaging/Manifest/Schema/2015/BundleManifestSchema2013.xsd"
"AppxPackaging/Manifest/Schema/2015/BundleManifestSchema2014.xsd"
"AppxPackaging/Manifest/Schema/2016/BundleManifestSchema2016.xsd"
"AppxPackaging/Manifest/Schema/2017/BundleManifestSchema2017.xsd")
endif(USE_VALIDATION_PARSER)
# Create zip file. Use execute_process to run the command while CMake is procesing.
message(STATUS "Resource files:")
foreach(FILE ${RESOURCES_BLOCKMAP} ${RESOURCES_CONTENTTYPE} ${RESOURCES_APPXMANIFEST} ${RESOURCES_CERTS})
foreach(FILE ${RESOURCES_BLOCKMAP} ${RESOURCES_CONTENTTYPE} ${RESOURCES_APPXMANIFEST} ${RESOURCES_CERTS} ${RESOURCES_APPXBUNDLEMANIFEST})
message(STATUS "\t${FILE}")
endforeach(FILE)
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar cvf "${CMAKE_BINARY_DIR}/resources.zip" --format=zip -- ${RESOURCES_BLOCKMAP} ${RESOURCES_CONTENTTYPE} ${RESOURCES_APPXMANIFEST} ${RESOURCES_CERTS}
COMMAND ${CMAKE_COMMAND} -E tar cvf "${CMAKE_BINARY_DIR}/resources.zip" --format=zip -- ${RESOURCES_BLOCKMAP} ${RESOURCES_CONTENTTYPE} ${RESOURCES_APPXMANIFEST} ${RESOURCES_CERTS} ${RESOURCES_APPXBUNDLEMANIFEST}
WORKING_DIRECTORY "${CMAKE_PROJECT_ROOT}/resources"
OUTPUT_QUIET
)
@ -98,10 +101,11 @@ function(GetResourceHpp LIST OUTPUT)
set(${OUTPUT} ${RESULT} PARENT_SCOPE)
endfunction()
GetResourceHpp("${RESOURCES_BLOCKMAP}" BLOCKMAP_HPP)
GetResourceHpp("${RESOURCES_CONTENTTYPE}" CONTENTTYPE_HPP)
GetResourceHpp("${RESOURCES_APPXMANIFEST}" APPXMANIFEST_HPP)
GetResourceHpp("${RESOURCES_CERTS}" CERTS_HPP)
GetResourceHpp("${RESOURCES_BLOCKMAP}" BLOCKMAP_HPP)
GetResourceHpp("${RESOURCES_CONTENTTYPE}" CONTENTTYPE_HPP)
GetResourceHpp("${RESOURCES_APPXMANIFEST}" APPXMANIFEST_HPP)
GetResourceHpp("${RESOURCES_CERTS}" CERTS_HPP)
GetResourceHpp("${RESOURCES_APPXBUNDLEMANIFEST}" APPXBUNDLEMANIFEST_HPP)
set(RESOURCE_HEADER "//
//
@ -122,7 +126,8 @@ namespace MSIX {
Certificates,
ContentType,
BlockMap,
AppxManifest
AppxManifest,
AppxBundleManifest
};
const size_t resourceLength = ${RESOURCE_LENGTH};
@ -146,6 +151,9 @@ namespace MSIX {
case Resource::AppxManifest:
${APPXMANIFEST_HPP}
break;
case Resource::AppxBundleManifest:
${APPXBUNDLEMANIFEST_HPP}
break;
}
return result;
}

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

@ -214,10 +214,11 @@ namespace MSIX {
AppxBlockMapObject(IMSIXFactory* factory, const ComPtr<IStream>& stream);
// IVerifierObject
const std::string& GetPublisher() override {NOTSUPPORTED;}
const std::string& GetPublisher() override { NOTSUPPORTED; }
bool HasStream() override { return !!m_stream; }
ComPtr<IStream> GetStream() override { return m_stream; }
ComPtr<IStream> GetValidationStream(const std::string& part, const ComPtr<IStream>& stream) override;
const std::string GetPackageFullName() override { NOTSUPPORTED; }
// IAppxBlockMapReader
HRESULT STDMETHODCALLTYPE GetFile(LPCWSTR filename, IAppxBlockMapFile **file) noexcept override;

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

@ -56,16 +56,16 @@ namespace MSIX {
std::string ResourceId;
std::string Architecture;
std::string Publisher;
std::string PublisherHash;
std::string PublisherId;
std::string GetPackageFullName()
{
return Name + "_" + Version + "_" + Architecture + "_" + ResourceId + "_" + PublisherHash;
return Name + "_" + Version + "_" + Architecture + "_" + ResourceId + "_" + PublisherId;
}
std::string GetPackageFamilyName()
{
return Name + "_" + PublisherHash;
return Name + "_" + PublisherId;
}
};
@ -80,9 +80,9 @@ namespace MSIX {
bool HasStream() override { return !!m_stream; }
ComPtr<IStream> GetStream() override { return m_stream; }
ComPtr<IStream> GetValidationStream(const std::string& part, const ComPtr<IStream>&) override { NOTSUPPORTED; }
const std::string GetPackageFullName() override { return m_packageId->GetPackageFullName(); }
AppxPackageId* GetPackageId() { return m_packageId.get(); }
std::string GetPackageFullName() { return m_packageId->GetPackageFullName(); }
protected:
ComPtr<IStream> m_stream;
@ -123,9 +123,11 @@ namespace MSIX {
ComPtr<IStream> GetFile(const std::string& fileName) override;
ComPtr<IStream> OpenFile(const std::string& fileName, MSIX::FileStream::Mode mode) override;
void CommitChanges() override;
protected:
// Helper methods
void VerifyFile(const ComPtr<IStream>& stream, const std::string& fileName, const ComPtr<IAppxBlockMapInternal>& blockMapInternal);
std::map<std::string, ComPtr<IStream>> m_streams;
MSIX_VALIDATION_OPTION m_validation = MSIX_VALIDATION_OPTION::MSIX_VALIDATION_OPTION_FULL;
@ -137,6 +139,9 @@ namespace MSIX {
std::vector<std::string> m_payloadFiles;
std::vector<std::string> m_footprintFiles;
std::vector<std::string> m_payloadPackages;
bool m_isBundle = false;
};
class AppxFilesEnumerator final : public MSIX::ComClass<AppxFilesEnumerator, IAppxFilesEnumerator>

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

@ -68,6 +68,7 @@ namespace MSIX {
bool HasStream() override { return !!m_stream; }
ComPtr<IStream> GetStream() override { return m_stream; }
ComPtr<IStream> GetValidationStream(const std::string& part, const ComPtr<IStream>& stream) override;
const std::string GetPackageFullName() override { NOTSUPPORTED; }
void ValidateDigestHeader(DigestHeader* header, std::size_t numberOfHashes, std::size_t modHashes);

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

@ -27,10 +27,8 @@ namespace MSIX {
ComPtr<IStream> GetFile(const std::string& fileName) override;
ComPtr<IStream> OpenFile(const std::string& fileName, MSIX::FileStream::Mode mode) override;
void CommitChanges() override;
protected:
std::map<std::string, ComPtr<IStream>> m_streams;
std::string m_root;
};//class DirectoryObject

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

@ -11,6 +11,6 @@ namespace MSIX {
class SHA256
{
public:
static bool ComputeHash(/*in*/ std::uint8_t *buffer, /*in*/ std::uint32_t cbBuffer, /*inout*/ std::vector<uint8_t>& hash);
static bool ComputeHash(std::uint8_t *buffer, std::uint32_t cbBuffer, std::vector<uint8_t>& hash);
};
}

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

@ -55,11 +55,6 @@ public:
// or read + update, then nullptr is returned. If the file is opened with write and it does not exist,
// then the file is created and an empty stream to the file is handed back to the caller.
virtual MSIX::ComPtr<IStream> OpenFile(const std::string& fileName, MSIX::FileStream::Mode mode) = 0;
// Some storage objects may operate under cache semantics and therefore require an explicit commit.
// Clients should explicitly call CommitChanges after all write operations into the object are complete.
// An implementation of this interface MAY be a no-op.
virtual void CommitChanges() = 0;
};
SpecializeUuidOfImpl(IStorageObject);

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

@ -5,11 +5,34 @@
#pragma once
#include <string>
#include <locale>
#include <codecvt>
namespace MSIX {
namespace MSIX {
/*
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
using StringType = std::basic_string<unsigned short>;
using StringConvert = std::wstring_convert<std::codecvt_utf8_utf16<unsigned short>, unsigned short>;
#else
using StringType = std::u16string;
using StringConvert = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>;
#endif
StringType utf8_to_utf16(const std::string& utf8string);
// converts an input utf8 formatted string into a utf16 formatted string
std::wstring utf8_to_utf16(const std::string& utf8string);
std::wstring utf8_to_wstring(const std::string& utf8string);
std::u16string utf8_to_u16string(const std::string& utf8string);
// converts an input utf16 formatted string into a utf8 formatted string
std::string utf16_to_utf8(const std::wstring& utf16string);

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

@ -27,6 +27,7 @@ public:
virtual bool HasStream() = 0;
virtual MSIX::ComPtr<IStream> GetStream() = 0;
virtual MSIX::ComPtr<IStream> GetValidationStream(const std::string& part, const MSIX::ComPtr<IStream>& stream) = 0;
virtual const std::string GetPackageFullName() = 0;
};
SpecializeUuidOfImpl(IVerifierObject);

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

@ -34,6 +34,12 @@ struct State
return true;
}
bool CreatePackageSubfolder()
{
unpackOptions = static_cast<MSIX_PACKUNPACK_OPTION>(unpackOptions | MSIX_PACKUNPACK_OPTION::MSIX_PACKUNPACK_OPTION_CREATEPACKAGESUBFOLDER);
return true;
}
bool SkipManifestValidation()
{
validationOptions = static_cast<MSIX_VALIDATION_OPTION>(validationOptions | MSIX_VALIDATION_OPTION::MSIX_VALIDATION_OPTION_SKIPAPPXMANIFEST);
@ -73,7 +79,8 @@ struct State
case UserSpecified::Unpack:
if (packageName.empty() || directoryName.empty()) {
return false;
}
}
break;
}
return true;
}
@ -266,6 +273,8 @@ int main(int argc, char* argv[])
[](State& state, const std::string& name) { return state.SetPackageName(name); }),
Option("-d", true, "REQUIRED, specify output directory name.",
[](State& state, const std::string& name) { return state.SetDirectoryName(name); }),
Option("-pfn", false, "Unpacks all files to a subdirectory under the specified output path, named after the package full name.",
[](State& state, const std::string&) {return state.CreatePackageSubfolder(); }),
Option("-mv", false, "Skips manifest validation. By default manifest validation is enabled.",
[](State& state, const std::string&) { return state.SkipManifestValidation(); }),
Option("-sv", false, "Skips signature validation. By default signature validation is enabled.",

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

@ -20,14 +20,16 @@
#include <algorithm>
#include <array>
namespace MSIX {
// names of footprint files.
#define APPXBLOCKMAP_XML "AppxBlockMap.xml"
#define APPXMANIFEST_XML "AppxManifest.xml"
#define CODEINTEGRITY_CAT "AppxMetadata/CodeIntegrity.cat"
#define APPXSIGNATURE_P7X "AppxSignature.p7x"
#define CONTENT_TYPES_XML "[Content_Types].xml"
#define APPXBLOCKMAP_XML "AppxBlockMap.xml"
#define APPXMANIFEST_XML "AppxManifest.xml"
#define CODEINTEGRITY_CAT "AppxMetadata/CodeIntegrity.cat"
#define APPXSIGNATURE_P7X "AppxSignature.p7x"
#define CONTENT_TYPES_XML "[Content_Types].xml"
#define APPXBUNDLEMANIFEST_XML "AppxMetadata/AppxBundleManifest.xml"
static const std::array<const char*, 4> footprintFiles =
{ APPXMANIFEST_XML,
@ -52,6 +54,9 @@ namespace MSIX {
nullptr, nullptr, nullptr, "%5B", nullptr, "%5D" // [ ]
};
// Douglas Crockford's base 32 alphabet variant is 0-9, A-Z except for i, l, o, and u.
static const char base32DigitList[] = "0123456789abcdefghjkmnpqrstvwxyz";
struct EncodingChar
{
const char* encode;
@ -106,6 +111,66 @@ namespace MSIX {
return result;
}
static std::string Base32Encoding(const std::vector<uint8_t>& bytes)
{
static const size_t publisherIdSize = 13;
static const size_t byteCount = 8;
// Consider groups of five bytes. This is the smallest number of bytes that has a number of bits
// that's evenly divisible by five.
// Every five bits starting with the most significant of the first byte are made into a base32 value.
// Each value is used to index into the alphabet array to produce a base32 digit.
// When out of bytes but the corresponding base32 value doesn't yet have five bits, 0 is used.
// Normally in these cases a particular number of '=' characters are appended to the resulting base32
// string to indicate how many bits didn't come from the actual byte value. For our purposes no
// such padding characters are necessary.
//
// Bytes: aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee
// Base32 Values: 000aaaaa 000aaabb 000bbbbb 000bcccc 000ccccd 000ddddd 000ddeee 000eeeee
//
// Combo of byte a & F8 a & 07 b & 3E b & 01 c & 0F d & 7C d & 03 e & 1F
// values except b & C0 c & F0 d & 80 e & E0
// for shifting
// Make sure the following math doesn't overflow.
char output[publisherIdSize+1] = "";
size_t outputIndex = 0;
for(size_t byteIndex = 0; byteIndex < byteCount; byteIndex +=5)
{
uint8_t firstByte = bytes[byteIndex];
uint8_t secondByte = (byteIndex + 1) < byteCount ? bytes[byteIndex + 1] : 0;
output[outputIndex++] = base32DigitList[(firstByte & 0xF8) >> 3];
output[outputIndex++] = base32DigitList[((firstByte & 0x07) << 2) | ((secondByte & 0xC0) >> 6)];
if(byteIndex + 1 < byteCount)
{
uint8_t thirdByte = (byteIndex + 2) < byteCount ? bytes[byteIndex + 2] : 0;
output[outputIndex++] = base32DigitList[(secondByte & 0x3E) >> 1];
output[outputIndex++] = base32DigitList[((secondByte & 0x01) << 4) | ((thirdByte & 0xF0) >> 4)];
if(byteIndex + 2 < byteCount)
{
uint8_t fourthByte = (byteIndex + 3) < byteCount ? bytes[byteIndex + 3] : 0;
output[outputIndex++] = base32DigitList[((thirdByte & 0x0F) << 1) | ((fourthByte & 0x80) >> 7)];
if (byteIndex + 3 < byteCount)
{
uint8_t fifthByte = (byteIndex + 4) < byteCount ? bytes[byteIndex + 4] : 0;
output[outputIndex++] = base32DigitList[(fourthByte & 0x7C) >> 2];
output[outputIndex++] = base32DigitList[((fourthByte & 0x03) << 3) | ((fifthByte & 0xE0) >> 5)];
if (byteIndex + 4 < byteCount)
{
output[outputIndex++] = base32DigitList[fifthByte & 0x1F];
}
}
}
}
}
output[publisherIdSize] = '\0';
return std::string(output);
}
AppxPackageId::AppxPackageId(
const std::string& name,
const std::string& version,
@ -118,7 +183,15 @@ namespace MSIX {
// Only name, publisher and version are required
ThrowErrorIf(Error::AppxManifestSemanticError, (Name.empty() || Version.empty() || Publisher.empty()), "Invalid Identity element");
// TODO: calculate the publisher hash from the publisher value.
// TODO: validate the name and resource id as package strings
auto wpublisher = utf8_to_u16string(publisher);
std::vector<std::uint8_t> buffer(wpublisher.size() * sizeof(char16_t));
memcpy(buffer.data(), &wpublisher[0], wpublisher.size() * sizeof(char16_t));
std::vector<std::uint8_t> hash;
ThrowErrorIfNot(Error::Unexpected, SHA256::ComputeHash(buffer.data(), buffer.size(), hash), "Failed computing publisherId");
PublisherId = Base32Encoding(hash);
}
AppxManifestObject::AppxManifestObject(IXmlFactory* factory, const ComPtr<IStream>& stream) : m_stream(stream)
@ -174,16 +247,32 @@ namespace MSIX {
// 4. Get manifest object using blockmap object for validation
// TODO: pass validation flags and other necessary goodness through.
file = m_container->GetFile(APPXMANIFEST_XML);
ThrowErrorIfNot(Error::MissingAppxManifestXML, file, "AppxManifest.xml not in archive!");
stream = m_appxBlockMap->GetValidationStream(APPXMANIFEST_XML, file);
m_appxManifest = ComPtr<IVerifierObject>::Make<AppxManifestObject>(xmlFactory.Get(), stream);
auto appxManifestInContainer = m_container->GetFile(APPXMANIFEST_XML);
auto appxBundleManifestInContainer = m_container->GetFile(APPXBUNDLEMANIFEST_XML);
if ((validation & MSIX_VALIDATION_OPTION_SKIPSIGNATURE) == 0)
ThrowErrorIfNot(Error::MissingAppxManifestXML, (appxManifestInContainer || appxBundleManifestInContainer) ,
"AppxManifest.xml or AppxBundleManifest.xml not in archive!");
ThrowErrorIf(Error::MissingAppxManifestXML, (appxManifestInContainer && appxBundleManifestInContainer) ,
"AppxManifest.xml and AppxBundleManifest.xml in archive!");
// We already validate that there's at least one and not both
if(appxManifestInContainer)
{
std::string reason = "Publisher mismatch: '" + m_appxManifest->GetPublisher() + "' != '" + m_appxSignature->GetPublisher() + "'";
ThrowErrorIfNot(Error::PublisherMismatch,
(0 == m_appxManifest->GetPublisher().compare(m_appxSignature->GetPublisher())), reason.c_str());
stream = m_appxBlockMap->GetValidationStream(APPXMANIFEST_XML, appxManifestInContainer);
m_appxManifest = ComPtr<IVerifierObject>::Make<AppxManifestObject>(xmlFactory.Get(), stream);
if ((m_validation & MSIX_VALIDATION_OPTION_SKIPSIGNATURE) == 0)
{
std::string reason = "Publisher mismatch: '" + m_appxManifest->GetPublisher() + "' != '" + m_appxSignature->GetPublisher() + "'";
ThrowErrorIfNot(Error::PublisherMismatch,
(0 == m_appxManifest->GetPublisher().compare(m_appxSignature->GetPublisher())), reason.c_str());
}
}
else
{
std::string pathInWindows(APPXBUNDLEMANIFEST_XML);
std::replace(pathInWindows.begin(), pathInWindows.end(), '/', '\\');
stream = m_appxBlockMap->GetValidationStream(pathInWindows, appxBundleManifestInContainer);
// TODO: create appxBundleManifestObject and validate
m_isBundle = true;
}
struct Config
@ -200,11 +289,12 @@ namespace MSIX {
};
static const Config footPrintFileNames[] = {
Config(APPXBLOCKMAP_XML, [](AppxPackageObject* self){ self->m_footprintFiles.push_back(APPXBLOCKMAP_XML); return self->m_appxBlockMap->GetStream();}),
Config(APPXMANIFEST_XML, [](AppxPackageObject* self){ self->m_footprintFiles.push_back(APPXMANIFEST_XML); return self->m_appxManifest->GetStream();}),
Config(APPXSIGNATURE_P7X, [](AppxPackageObject* self){ if (self->m_appxSignature->HasStream()){self->m_footprintFiles.push_back(APPXSIGNATURE_P7X);} return self->m_appxSignature->GetStream();}),
Config(CODEINTEGRITY_CAT, [](AppxPackageObject* self){ self->m_footprintFiles.push_back(CODEINTEGRITY_CAT); auto file = self->m_container->GetFile(CODEINTEGRITY_CAT); return self->m_appxSignature->GetValidationStream(CODEINTEGRITY_CAT, file);}),
Config(CONTENT_TYPES_XML, [](AppxPackageObject*)->ComPtr<IStream>{ return ComPtr<IStream>();}), // content types is never implicitly unpacked
Config(APPXBLOCKMAP_XML, [](AppxPackageObject* self){ self->m_footprintFiles.push_back(APPXBLOCKMAP_XML); return self->m_appxBlockMap->GetStream();}),
Config(APPXMANIFEST_XML, [](AppxPackageObject* self){ self->m_footprintFiles.push_back(APPXMANIFEST_XML); return self->m_appxManifest->GetStream();}),
Config(APPXSIGNATURE_P7X, [](AppxPackageObject* self){ if (self->m_appxSignature->HasStream()){self->m_footprintFiles.push_back(APPXSIGNATURE_P7X);} return self->m_appxSignature->GetStream();}),
Config(CODEINTEGRITY_CAT, [](AppxPackageObject* self){ self->m_footprintFiles.push_back(CODEINTEGRITY_CAT); auto file = self->m_container->GetFile(CODEINTEGRITY_CAT); return self->m_appxSignature->GetValidationStream(CODEINTEGRITY_CAT, file);}),
Config(CONTENT_TYPES_XML, [](AppxPackageObject*)->ComPtr<IStream>{ return ComPtr<IStream>();}), // content types is never implicitly unpacked
Config(APPXBUNDLEMANIFEST_XML, [](AppxPackageObject* self){ self->m_footprintFiles.push_back(APPXBUNDLEMANIFEST_XML); return /*self->m_appxBundleManifest->GetStream()*/ self->m_container->GetFile(APPXBUNDLEMANIFEST_XML);}),
};
// 5. Ensure that the stream collection contains streams wired up for their appropriate validation
@ -218,71 +308,99 @@ namespace MSIX {
filesToProcess.erase(std::remove(filesToProcess.begin(), filesToProcess.end(), fileName), filesToProcess.end());
}
}
auto blockMapInternal = m_appxBlockMap.As<IAppxBlockMapInternal>();
for (const auto& fileName : blockMapInternal->GetFileNames())
{ auto footPrintFile = std::find(std::begin(footPrintFileNames), std::end(footPrintFileNames), fileName);
if (footPrintFile == std::end(footPrintFileNames))
{ std::string containerFileName = EncodeFileName(fileName);
m_payloadFiles.push_back(containerFileName);
auto fileStream = m_container->GetFile(containerFileName);
ThrowErrorIf(Error::FileNotFound, !fileStream, "File described in blockmap not contained in OPC container");
// Verify file in OPC and BlockMap
ComPtr<IAppxFile> appxFile = fileStream.As<IAppxFile>();
APPX_COMPRESSION_OPTION compressionOpt;
ThrowHrIfFailed(appxFile->GetCompressionOption(&compressionOpt));
bool isUncompressed = (compressionOpt == APPX_COMPRESSION_OPTION_NONE);
ComPtr<IAppxFileInternal> appxFileInternal = fileStream.As<IAppxFileInternal>();
auto sizeOnZip = appxFileInternal->GetCompressedSize();
auto blocks = blockMapInternal->GetBlocks(fileName);
std::uint64_t blocksSize = 0;
for(auto& block : blocks)
{ // For Block elements that don't have a Size attribute, we always set its size as BLOCKMAP_BLOCK_SIZE
// (even for the last one). The Size attribute isn't specified if the file is not compressed.
ThrowErrorIf(Error::BlockMapSemanticError, isUncompressed && (block.compressedSize != BLOCKMAP_BLOCK_SIZE),
"An uncompressed file has a size attribute in its Block elements");
blocksSize += block.compressedSize;
auto blockMapFiles = blockMapInternal->GetFileNames();
if(m_isBundle)
{
// There should only be one file in the blockmap for bundles. We validate that the block map contains
// AppxMetadata/AppxBundleManifest.xml before, so just check the size.
ThrowErrorIfNot(Error::BlockMapSemanticError, ((blockMapFiles.size() == 1)), "Block map contains invalid files.");
// TODO: change this to get the files in from the bundle manifest and compare with m_container when the parsing is done.
for (const auto& fileName : m_container->GetFileNames(FileNameOptions::PayloadOnly))
{ auto footPrintFile = std::find(std::begin(footPrintFileNames), std::end(footPrintFileNames), fileName);
if (footPrintFile == std::end(footPrintFileNames))
{
m_payloadPackages.push_back(fileName);
m_streams[fileName] = std::move(m_container->GetFile(fileName));
filesToProcess.erase(std::remove(filesToProcess.begin(), filesToProcess.end(), fileName), filesToProcess.end());
}
if(isUncompressed)
{ UINT64 blockMapFileSize;
auto blockMapFile = blockMapInternal->GetFile(fileName);
ThrowHrIfFailed(blockMapFile->GetUncompressedSize(&blockMapFileSize));
ThrowErrorIf(Error::BlockMapSemanticError, (blockMapFileSize != sizeOnZip ),
"Uncompressed size of the file in the block map and the OPC container don't match");
}
else
{ // From Windows code:
// The file item is compressed. There are 2 cases here:
// 1. The compressed size of the file is the same as the total size of all compressed blocks.
// 2. The compressed size of the file is 2 bytes more than the total size of all compressed blocks.
// It depends on how the block compression is done. MakeAppx block compression implementation will end up
// with case 2. However, we shouldn't block the first case since it is totally valid and 3rd party
// implementation may end up with it.
// The reason we created compressed file item with 2 extra bytes (03 00) is because we use Z_FULL_FLUSH
// flag to compress every block. If we use Z_FINISH flag to compress the last block, these 2 extra bytes will
// not be generated. The AddBlock()-->... -->AddBlock()-->Close() pattern in OPC push stack prevents the
// deflator from knowing whether the current block is the last block. So it cannot use Z_FINISH flag for
// the last block of the file. Note that removing the 2 extra bytes from the compressed file data will make
// it invalid when consumed by popular zip tools like WinZip and ShellZip. So they are required for the
// packages we created.
ThrowErrorIfNot(Error::BlockMapSemanticError,
(blocksSize == sizeOnZip ) // case 1
|| (blocksSize == sizeOnZip - 2), // case 2
"Compressed size of the file in the block map and the OPC container don't match");
}
m_streams[containerFileName] = m_appxBlockMap->GetValidationStream(fileName, fileStream);
filesToProcess.erase(std::remove(filesToProcess.begin(), filesToProcess.end(), containerFileName), filesToProcess.end());
}
}
else
{
for (const auto& fileName : blockMapFiles)
{ auto footPrintFile = std::find(std::begin(footPrintFileNames), std::end(footPrintFileNames), fileName);
if (footPrintFile == std::end(footPrintFileNames))
{ std::string containerFileName = EncodeFileName(fileName);
m_payloadFiles.push_back(containerFileName);
auto fileStream = m_container->GetFile(containerFileName);
ThrowErrorIfNot(Error::FileNotFound, fileStream, "File described in blockmap not contained in OPC container");
VerifyFile(fileStream, fileName, blockMapInternal);
m_streams[containerFileName] = m_appxBlockMap->GetValidationStream(fileName, fileStream);
filesToProcess.erase(std::remove(filesToProcess.begin(), filesToProcess.end(), containerFileName), filesToProcess.end());
}
}
}
// If the map is not empty, there's a file in the container that didn't go to the footprint or payload
// files. (eg. payload file missing in the AppxBlockMap.xml)
ThrowErrorIfNot(Error::BlockMapSemanticError, (filesToProcess.empty()), "Payload file not described in AppxBlockMap.xml");
}
// Verify file in OPC and BlockMap
void AppxPackageObject::VerifyFile(const ComPtr<IStream>& stream, const std::string& fileName, const ComPtr<IAppxBlockMapInternal>& blockMapInternal)
{
ComPtr<IAppxFile> appxFile = stream.As<IAppxFile>();;
APPX_COMPRESSION_OPTION compressionOpt;
ThrowHrIfFailed(appxFile->GetCompressionOption(&compressionOpt));
bool isUncompressed = (compressionOpt == APPX_COMPRESSION_OPTION_NONE);
ComPtr<IAppxFileInternal> appxFileInternal = stream.As<IAppxFileInternal>();
auto sizeOnZip = appxFileInternal->GetCompressedSize();
auto blocks = blockMapInternal->GetBlocks(fileName);
std::uint64_t blocksSize = 0;
for(auto& block : blocks)
{ // For Block elements that don't have a Size attribute, we always set its size as BLOCKMAP_BLOCK_SIZE
// (even for the last one). The Size attribute isn't specified if the file is not compressed.
ThrowErrorIf(Error::BlockMapSemanticError, isUncompressed && (block.compressedSize != BLOCKMAP_BLOCK_SIZE),
"An uncompressed file has a size attribute in its Block elements");
blocksSize += block.compressedSize;
}
if(isUncompressed)
{
UINT64 blockMapFileSize;
auto blockMapFile = blockMapInternal->GetFile(fileName);
ThrowHrIfFailed(blockMapFile->GetUncompressedSize(&blockMapFileSize));
ThrowErrorIf(Error::BlockMapSemanticError, (blockMapFileSize != sizeOnZip ),
"Uncompressed size of the file in the block map and the OPC container don't match");
}
else
{
// From Windows code:
// The file item is compressed. There are 2 cases here:
// 1. The compressed size of the file is the same as the total size of all compressed blocks.
// 2. The compressed size of the file is 2 bytes more than the total size of all compressed blocks.
// It depends on how the block compression is done. MakeAppx block compression implementation will end up
// with case 2. However, we shouldn't block the first case since it is totally valid and 3rd party
// implementation may end up with it.
// The reason we created compressed file item with 2 extra bytes (03 00) is because we use Z_FULL_FLUSH
// flag to compress every block. If we use Z_FINISH flag to compress the last block, these 2 extra bytes will
// not be generated. The AddBlock()-->... -->AddBlock()-->Close() pattern in OPC push stack prevents the
// deflator from knowing whether the current block is the last block. So it cannot use Z_FINISH flag for
// the last block of the file. Note that removing the 2 extra bytes from the compressed file data will make
// it invalid when consumed by popular zip tools like WinZip and ShellZip. So they are required for the
// packages we created.
ThrowErrorIfNot(Error::BlockMapSemanticError,
(blocksSize == sizeOnZip ) // case 1
|| (blocksSize == sizeOnZip - 2), // case 2
"Compressed size of the file in the block map and the OPC container don't match");
}
}
void AppxPackageObject::Unpack(MSIX_PACKUNPACK_OPTION options, const ComPtr<IStorageObject>& to)
{
auto fileNames = GetFileNames(FileNameOptions::All);
@ -290,8 +408,12 @@ namespace MSIX {
{
std::string targetName;
if (options & MSIX_PACKUNPACK_OPTION_CREATEPACKAGESUBFOLDER)
{ //targetName = GetAppxManifest()->GetPackageFullName() + to->GetPathSeparator() + fileName;
NOTIMPLEMENTED;
{ // Don't use to->GetPathSeparator(). DirectoryObject::OpenFile created directories
// by looking at "/" in the string. If to->GetPathSeparator() is used the subfolder with
// the package full name won't be created on Windows, but it will on other platforms.
// This means that we have different behaviors in non-Win platforms.
// TODO: have the same behavior on Windows and other platforms.
targetName = m_appxManifest->GetPackageFullName() + "/" + fileName;
}
else
{ targetName = DecodeFileName(fileName);
@ -304,6 +426,18 @@ namespace MSIX {
bytesCount.QuadPart = std::numeric_limits<std::uint64_t>::max();
ThrowHrIfFailed(sourceFile->CopyTo(targetFile.Get(), bytesCount, nullptr, nullptr));
}
if(m_isBundle)
{
for(const auto& appx : m_payloadPackages)
{
auto appxStream = GetFile(appx);
auto appxFactory = m_factory.As<IAppxFactory>();
ComPtr<IAppxPackageReader> reader;
ThrowHrIfFailed(appxFactory->CreatePackageReader(appxStream.Get(), &reader));
reader.As<IPackage>()->Unpack(
static_cast<MSIX_PACKUNPACK_OPTION>(options | MSIX_PACKUNPACK_OPTION_CREATEPACKAGESUBFOLDER), to.Get());
}
}
}
const char* AppxPackageObject::GetPathSeparator() { return "/"; }
@ -334,7 +468,6 @@ namespace MSIX {
}
ComPtr<IStream> AppxPackageObject::OpenFile(const std::string& fileName, MSIX::FileStream::Mode mode) { NOTIMPLEMENTED; }
void AppxPackageObject::CommitChanges() { NOTIMPLEMENTED; }
// IAppxPackageReader
HRESULT STDMETHODCALLTYPE AppxPackageObject::GetBlockMap(IAppxBlockMapReader** blockMapReader) noexcept
@ -405,6 +538,7 @@ namespace MSIX {
HRESULT STDMETHODCALLTYPE AppxPackageObject::GetPayloadPackage(LPCWSTR fileName, IAppxFile **payloadPackage) noexcept try
{
// TODO: Implement
return static_cast<HRESULT>(Error::NotImplemented);
} CATCH_RETURN();
}

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

@ -52,13 +52,7 @@ namespace MSIX {
std::string path = name.substr(0, lastSlash);
mkdirp(path);
auto result = ComPtr<IStream>::Make<FileStream>(std::move(name), mode);
m_streams[fileName] = result.Get(); // now cache the result in m_streams.
return result;
}
void DirectoryObject::CommitChanges()
{
m_streams.clear();
}
}
#endif

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

@ -41,7 +41,7 @@ namespace MSIX {
static std::string dot(".");
static std::string dotdot("..");
std::wstring utf16Name = utf8_to_utf16(root);
std::wstring utf16Name = utf8_to_wstring(root);
WIN32_FIND_DATA findFileData = {};
std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&::FindClose)> find(
@ -159,7 +159,7 @@ namespace MSIX {
if (!found)
{
std::wstring utf16Name = utf8_to_utf16(path + GetPathSeparator() + directories.front());
std::wstring utf16Name = utf8_to_wstring(path + GetPathSeparator() + directories.front());
if (!CreateDirectory(utf16Name.c_str(), nullptr))
{
auto lastError = GetLastError();
@ -171,14 +171,8 @@ namespace MSIX {
}
name = path + GetPathSeparator() + name;
auto result = ComPtr<IStream>::Make<FileStream>(std::move(name), mode);
m_streams[fileName] = result.Get(); // now cache the result in m_streams.
return result;
}
void DirectoryObject::CommitChanges()
{
m_streams.clear();
}
}
// Don't pollute other compilation units with any of our #defs...

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

@ -8,10 +8,7 @@
#include "openssl/sha.h"
namespace MSIX {
bool SHA256::ComputeHash(
/*in*/ std::uint8_t *buffer,
/*in*/ std::uint32_t cbBuffer,
/*inout*/ std::vector<uint8_t>& hash)
bool SHA256::ComputeHash(std::uint8_t *buffer, std::uint32_t cbBuffer, std::vector<uint8_t>& hash)
{
hash.resize(SHA256_DIGEST_LENGTH);
::SHA256(buffer, cbBuffer, hash.data());

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

@ -65,7 +65,7 @@ namespace MSIX {
ThrowStatusIfFailed(BCryptGetProperty(
algHandle.get(), // Handle to a CNG object
BCRYPT_HASH_LENGTH, // Property name (null terminated unicode string)
(PBYTE)&hashLength, // Address of the output buffer which recieves the property value
(PBYTE)&hashLength, // Address of the output buffer which receives the property value
sizeof(hashLength), // Size of the buffer in bytes
&resultLength, // Number of bytes that were copied into the buffer
0), // Flags
@ -79,7 +79,7 @@ namespace MSIX {
ThrowStatusIfFailed(BCryptCreateHash(
algHandle.get(), // Handle to an algorithm provider
&hashHandleT, // A pointer to a hash handle - can be a hash or hmac object
nullptr, // Pointer to the buffer that recieves the hash/hmac object
nullptr, // Pointer to the buffer that receives the hash/hmac object
0, // Size of the buffer in bytes
nullptr, // A pointer to a key to use for the hash or MAC
0, // Size of the key in bytes

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

@ -245,7 +245,7 @@ public:
{
std::vector<std::uint8_t> result;
auto intermediate = GetAttributeValue(attribute);;
auto intermediate = GetAttributeValue(attribute);
ThrowErrorIfNot(Error::InvalidParameter, (0 == (intermediate.length() % 4)), "invalid base64 encoding");
for(std::size_t index=0; index < intermediate.length(); index += 4)
{

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

@ -5,33 +5,29 @@
#include <memory>
#include <iostream>
#include <sstream>
#include <locale>
#include <codecvt>
#include "UnicodeConversion.hpp"
namespace MSIX {
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
StringType utf8_to_utf16(const std::string& utf8string)
{
return StringConvert{}.from_bytes(utf8string.data());
}
std::wstring utf8_to_wstring(const std::string& utf8string)
{
auto converted = utf8_to_utf16(utf8string);
std::wstring result(converted.begin(), converted.end());
return result;
}
std::u16string utf8_to_u16string(const std::string& utf8string)
{
auto converted = utf8_to_utf16(utf8string);
std::u16string 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());

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

@ -12,7 +12,7 @@ function FindBinFolder {
elif [ -e "../../build/bin/makemsix" ]
then
BINDIR="../../build/bin"
else
else
echo "ERROR: Could not find build binaries"
exit 2
fi
@ -40,7 +40,7 @@ function RunTest {
echo "expect: "$SUCCESS", got: "$RESULT
if [ $RESULT -eq $SUCCESS ]
then
echo "succeeded"
echo "succeeded"
else
echo "FAILED"
TESTFAILED=1
@ -77,6 +77,35 @@ RunTest 51 ./../appx/BlockMap/No_blockmap.appx -ss
RunTest 3 ./../appx/BlockMap/Bad_Namespace_Blockmap.appx -ss
RunTest 81 ./../appx/BlockMap/Duplicate_file_in_blockmap.appx -ss
# Bundle tests
RunTest 81 ./../appx/bundles/BlockMapContainsPayloadPackage.appxbundle -ss
RunTest 51 ./../appx/bundles/BlockMapIsMissing.appxbundle -ss
#RunTest 0 ./../appx/bundles/BlockMapViolatesSchema.appxbundle
#RunTest 0 ./../appx/bundles/ContainsNeutralAndX86AppPackages.appxbundle
#RunTest 0 ./../appx/bundles/ContainsNoPayload.appxbundle
#RunTest 0 ./../appx/bundles/ContainsOnlyResourcePackages.appxbundle
#RunTest 0 ./../appx/bundles/ContainsTwoNeutralAppPackages.appxbundle
RunTest 0 ./../appx/bundles/MainBundle.appxbundle -ss
#RunTest 0 ./../appx/bundles/ManifestDeclaresAppPackageForResourcePackage.appxbundle
#RunTest 0 ./../appx/bundles/ManifestDeclaresResourcePackageForAppPackage.appxbundle
#RunTest 0 ./../appx/bundles/ManifestHasExtraPackage.appxbundle
RunTest 52 ./../appx/bundles/ManifestIsMissing.appxbundle -ss
#RunTest 0 ./../appx/bundles/ManifestPackageHasIncorrectArchitecture.appxbundle
#RunTest 0 ./../appx/bundles/ManifestPackageHasIncorrectName.appxbundle
#RunTest 0 ./../appx/bundles/ManifestPackageHasIncorrectPublisher.appxbundle
#RunTest 0 ./../appx/bundles/ManifestPackageHasIncorrectSize.appxbundle
#RunTest 0 ./../appx/bundles/ManifestPackageHasIncorrectVersion.appxbundle
#RunTest 0 ./../appx/bundles/ManifestPackageHasInvalidOffset.appxbundle
#RunTest 0 ./../appx/bundles/ManifestPackageHasInvalidRange.appxbundle
#RunTest 0 ./../appx/bundles/ManifestViolatesSchema.appxbundle
#RunTest 0 ./../appx/bundles/PayloadPackageHasNonAppxExtension.appxbundle
#RunTest 0 ./../appx/bundles/PayloadPackageIsCompressed.appxbundle
#RunTest 0 ./../appx/bundles/PayloadPackageIsEmpty.appxbundle.zip
#RunTest 0 ./../appx/bundles/PayloadPackageIsNotAppxPackage.appxbundle
#RunTest 0 ./../appx/bundles/PayloadPackageNotListedInManifest.appxbundle
RunTest 66 ./../appx/bundles/SignedUntrustedCert-CERT_E_CHAINING.appxbundle
RunTest 0 ./../appx/bundles/StoreSigned_Desktop_x86_x64_MoviesTV.appxbundle
echo "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
if [ $TESTFAILED -ne 0 ]
then

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

@ -93,6 +93,35 @@ RunTest 0x8bad0033 .\..\appx\BlockMap\No_blockmap.appx "-ss"
RunTest 0x8bad1003 .\..\appx\BlockMap\Bad_Namespace_Blockmap.appx "-ss"
RunTest 0x8bad0051 .\..\appx\BlockMap\Duplicate_file_in_blockmap.appx "-ss"
# Bundle tests
RunTest 0x8bad0051 .\..\appx\bundles\BlockMapContainsPayloadPackage.appxbundle "-ss"
RunTest 0x8bad0033 .\..\appx\bundles\BlockMapIsMissing.appxbundle "-ss"
#RunTest 0x00000000 .\..\appx\bundles\BlockMapViolatesSchema.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ContainsNeutralAndX86AppPackages.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ContainsNoPayload.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ContainsOnlyResourcePackages.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ContainsTwoNeutralAppPackages.appxbundle
RunTest 0x00000000 .\..\appx\bundles\MainBundle.appxbundle "-ss"
#RunTest 0x00000000 .\..\appx\bundles\ManifestDeclaresAppPackageForResourcePackage.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestDeclaresResourcePackageForAppPackage.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestHasExtraPackage.appxbundle
RunTest 0x8bad0034 .\..\appx\bundles\ManifestIsMissing.appxbundle "-ss"
#RunTest 0x00000000 .\..\appx\bundles\ManifestPackageHasIncorrectArchitecture.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestPackageHasIncorrectName.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestPackageHasIncorrectPublisher.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestPackageHasIncorrectSize.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestPackageHasIncorrectVersion.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestPackageHasInvalidOffset.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestPackageHasInvalidRange.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\ManifestViolatesSchema.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\PayloadPackageHasNonAppxExtension.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\PayloadPackageIsCompressed.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\PayloadPackageIsEmpty.appxbundle.zip
#RunTest 0x00000000 .\..\appx\bundles\PayloadPackageIsNotAppxPackage.appxbundle
#RunTest 0x00000000 .\..\appx\bundles\PayloadPackageNotListedInManifest.appxbundle
RunTest 0x8bad0042 .\..\appx\bundles\SignedUntrustedCert-CERT_E_CHAINING.appxbundle
RunTest 0x00000000 .\..\appx\bundles\StoreSigned_Desktop_x86_x64_MoviesTV.appxbundle
CleanupUnpackFolder
write-host "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Двоичные данные
test/appx/bundles/SignedUntrustedCert-CERT_E_CHAINING.appxbundle Normal file

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

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

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

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

@ -78,6 +78,7 @@ Java_com_microsoft_androidbvt_MainActivity_RunTests(JNIEnv* env, jobject /* this
std::string filePath = GetStringPathFromJString(env, jFilePath);
CopyFilesFromAssets(env, assetManager, filePath, "");
CopyFilesFromAssets(env, assetManager, filePath, "BlockMap");
CopyFilesFromAssets(env, assetManager, filePath, "bundles");
signed long hr = RunTests(const_cast<char*>(filePath.c_str()), const_cast<char*>(filePath.c_str()));
if(hr == 0)
{

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

@ -381,6 +381,35 @@ static HRESULT RunTestsInternal(std::string source, std::string target)
hr = RunTest(source + "BlockMap/Bad_Namespace_Blockmap.appx", unpackFolder, ss, 4099);
hr = RunTest(source + "BlockMap/Duplicate_file_in_blockmap.appx", unpackFolder, ss, 81);
// Bundle tests
hr = RunTest(source + "bundles/BlockMapContainsPayloadPackage.appxbundle", unpackFolder, ss, 81);
hr = RunTest(source + "bundles/BlockMapIsMissing.appxbundle", unpackFolder, ss, 51);
//hr = RunTest(source + "bundles/BlockMapViolatesSchema.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ContainsNeutralAndX86AppPackages.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ContainsNoPayload.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ContainsOnlyResourcePackages.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ContainsTwoNeutralAppPackages.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/MainBundle.appxbundle", unpackFolder, ss, 0 );
//hr = RunTest(source + "bundles/ManifestDeclaresAppPackageForResourcePackage.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestDeclaresResourcePackageForAppPackage.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestHasExtraPackage.appxbundle", unpackFolder, full, 0);
hr = RunTest(source + "bundles/ManifestIsMissing.appxbundle", unpackFolder, ss, 52);
//hr = RunTest(source + "bundles/ManifestPackageHasIncorrectArchitecture.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestPackageHasIncorrectName.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestPackageHasIncorrectPublisher.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestPackageHasIncorrectSize.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestPackageHasIncorrectVersion.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestPackageHasInvalidOffset.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestPackageHasInvalidRange.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/ManifestViolatesSchema.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/PayloadPackageHasNonAppxExtension.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/PayloadPackageIsCompressed.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/PayloadPackageIsEmpty.appxbundle.zip", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/PayloadPackageIsNotAppxPackage.appxbundle", unpackFolder, full, 0);
//hr = RunTest(source + "bundles/PayloadPackageNotListedInManifest.appxbundle", unpackFolder, full, 0);
hr = RunTest(source + "bundles/SignedUntrustedCert-CERT_E_CHAINING.appxbundle", unpackFolder, full, 66);
//hr = RunTest(source + "bundles/StoreSigned_Desktop_x86_x64_MoviesTV.appxbundle", unpackFolder, full, 0);
std::cout << "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" << std::endl;
if(g_TestFailed)
{ std::cout << " FAILED " << std::endl;