Files
App-Installer-For-Windows-8…/AppxPackage/ManifestReader.cs

1001 lines
29 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using AppxPackage.Info;
using NativeWrappers;
using System.IO;
namespace AppxPackage
{
public static class DataUrlHelper
{
[DllImport ("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int FindMimeFromData (
IntPtr pBC,
string pwzUrl,
byte [] pBuffer,
int cbSize,
string pwzMimeProposed,
int dwMimeFlags,
out IntPtr ppwzMimeOut,
int dwReserved);
private const int FMFD_RETURNUPDATEDIMGMIMES = 0x00000001;
private const int FMFD_IGNOREMIMETEXTPLAIN = 0x00000010;
private const int FMFD_URLASFILENAME = 0x00000020;
private static string GetMimeTypeFromStream (Stream stream)
{
if (stream == null) return string.Empty;
long originalPos = 0;
try
{
if (stream.CanSeek)
{
originalPos = stream.Position;
stream.Seek (0, SeekOrigin.Begin);
}
byte [] buffer = new byte [256];
int bytesRead = stream.Read (buffer, 0, buffer.Length);
if (stream.CanSeek) stream.Seek (originalPos, SeekOrigin.Begin);
if (bytesRead == 0) return string.Empty;
IntPtr mimePtr;
int hr = FindMimeFromData (
IntPtr.Zero,
null,
buffer,
bytesRead,
null,
FMFD_RETURNUPDATEDIMGMIMES | FMFD_IGNOREMIMETEXTPLAIN | FMFD_URLASFILENAME,
out mimePtr,
0);
string mime = string.Empty;
if (hr == 0 && mimePtr != IntPtr.Zero)
{
mime = Marshal.PtrToStringUni (mimePtr);
Marshal.FreeCoTaskMem (mimePtr);
}
if (string.IsNullOrEmpty (mime))
{
// fallback by magic bytes
if (bytesRead >= 8 && buffer [0] == 0x89 && buffer [1] == 0x50 && buffer [2] == 0x4E && buffer [3] == 0x47 &&
buffer [4] == 0x0D && buffer [5] == 0x0A && buffer [6] == 0x1A && buffer [7] == 0x0A)
mime = "image/png";
else if (bytesRead >= 3 && buffer [0] == 0xFF && buffer [1] == 0xD8)
mime = "image/jpeg";
else if (bytesRead >= 6 && Encoding.ASCII.GetString (buffer, 0, 6) == "GIF89a")
mime = "image/gif";
else if (bytesRead >= 2 && buffer [0] == 'B' && buffer [1] == 'M')
mime = "image/bmp";
else if (bytesRead >= 12 && Encoding.ASCII.GetString (buffer, 0, 4) == "RIFF" &&
Encoding.ASCII.GetString (buffer, 8, 4) == "WEBP")
mime = "image/webp";
else if (bytesRead >= 4 && buffer [0] == 0x00 && buffer [1] == 0x00 && buffer [2] == 0x01 && buffer [3] == 0x00)
mime = "image/x-icon";
else
mime = "application/octet-stream";
}
return mime;
}
catch
{
return string.Empty;
}
}
public static string FileToDataUrl (string filePath)
{
if (string.IsNullOrEmpty (filePath)) return string.Empty;
try
{
using (FileStream fs = new FileStream (filePath, FileMode.Open, FileAccess.Read))
{
if (fs.Length == 0) return string.Empty;
string mime = GetMimeTypeFromStream (fs);
if (string.IsNullOrEmpty (mime)) return string.Empty;
byte [] bytes = new byte [fs.Length];
fs.Seek (0, SeekOrigin.Begin);
int read = fs.Read (bytes, 0, bytes.Length);
if (read != bytes.Length) return string.Empty;
string base64 = Convert.ToBase64String (bytes);
return $"data:{mime};base64,{base64}";
}
}
catch
{
return string.Empty;
}
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class BaseInfoSectWithPRISingle: BaseInfoSection
{
protected Ref<ManifestReader> m_reader = null;
protected Ref<PriReader> m_pri = null;
protected Ref<bool> m_usePri = false;
protected Ref<bool> m_enablePri = false;
public BaseInfoSectWithPRISingle (ref IntPtr hReader, ManifestReader reader, ref PriReader pri, ref bool usePri, ref bool enablePri) : base (ref hReader)
{
m_reader.Set (reader);
m_pri.Set (pri);
m_usePri.Set (usePri);
m_enablePri.Set (enablePri);
}
public new void Dispose ()
{
try { m_reader.Set (null); } catch (Exception) { }
try { m_pri.Set (null); } catch (Exception) { }
m_usePri = null;
m_enablePri = null;
m_hReader = null;
}
~BaseInfoSectWithPRISingle () { Dispose (); }
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class MRIdentity: BaseInfoSection, Info.IIdentity
{
public MRIdentity (ref IntPtr hReader) : base (ref hReader) { }
protected string StringValue (uint name)
{
var ptr = PackageReadHelper.GetManifestIdentityStringValue (m_hReader, name);
return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? "";
}
public string FamilyName { get { return StringValue (2); } }
public string FullName { get { return StringValue (3); } }
public string Name { get { return StringValue (0); } }
public List<Architecture> ProcessArchitecture
{
get
{
var list = new List<Architecture> ();
uint uarch = 0;
PackageReadHelper.GetManifestIdentityArchitecture (m_hReader, out uarch);
var t = PackageReadHelper.GetManifestType (m_hReader);
switch (t)
{
case 1:
switch (uarch)
{
case 0x1: list.Add (Architecture.x86); break;
case 0x2: list.Add (Architecture.x64); break;
case 0x4: list.Add (Architecture.ARM); break;
case 0x8: list.Add (Architecture.ARM64); break;
case 0xE: list.Add (Architecture.Neutral); break;
}
break;
case 2:
if ((uarch & 0x1) != 0) list.Add (Architecture.x86);
if ((uarch & 0x2) != 0) list.Add (Architecture.x64);
if ((uarch & 0x4) != 0) list.Add (Architecture.ARM);
if ((uarch & 0x8) != 0) list.Add (Architecture.ARM64);
break;
}
return list;
}
}
public string Publisher { get { return StringValue (1); } }
public string ResourceId { get { return StringValue (4); } }
public DataUtils.Version Version
{
get
{
PackageReadHelper.VERSION ver = new PackageReadHelper.VERSION ();
PackageReadHelper.GetManifestIdentityVersion (m_hReader, out ver);
return new DataUtils.Version (ver.major, ver.minor, ver.build, ver.revision);
}
}
public override object BuildJSON ()
{
return new
{
name = Name,
package_full_name = FullName,
package_family_name = FamilyName,
publisher = Publisher,
resource_id = ResourceId,
architecture = ProcessArchitecture.Select (e => (int)e).ToList (),
version = Version.BuildJSON ()
};
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class MRProperties: BaseInfoSectWithPRISingle, Info.IProperties
{
public MRProperties (ref IntPtr hReader, ManifestReader reader, ref PriReader priBundle, ref bool usePri, ref bool enablePri) : base (ref hReader, reader, ref priBundle, ref usePri, ref enablePri) { }
protected string StringValue (string attr)
{
var ptr = PackageReadHelper.GetManifestPropertiesStringValue (m_hReader, attr);
return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? "";
}
protected bool BoolValue (string attr, bool defaultValue = false)
{
int ret = 0;
HRESULT hr = PackageReadHelper.GetManifestPropertiesBoolValue (m_hReader, attr, out ret);
if (hr.Succeeded) return ret != 0;
else return defaultValue;
}
protected string StringResValue (string attr)
{
var res = StringValue (attr);
try
{
if (m_usePri && m_enablePri)
{
if (PriFileHelper.IsMsResourcePrefix (res))
return m_pri.Value.String (res) ?? res;
}
}
catch (Exception) { }
return res;
}
protected string PathResValue (string attr)
{
var res = StringValue (attr);
try
{
if (m_usePri && m_enablePri)
{
var resvalue = m_pri.Value.String (res);
if (!string.IsNullOrEmpty (resvalue)) return resvalue;
else return res;
}
}
catch (Exception) { }
return res;
}
public string Description { get { return StringResValue ("Description"); } }
public string DisplayName { get { return StringResValue ("DisplayName"); } }
public bool Framework { get { return BoolValue ("Framework"); } }
public string Logo { get { return PathResValue ("Logo"); } }
public string LogoBase64
{
get
{
var root = m_reader.Value.FileRoot;
var logopath = Path.Combine (root, Logo);
var ret = DataUrlHelper.FileToDataUrl (logopath);
if (!string.IsNullOrWhiteSpace (ret)) return ret;
logopath = Path.Combine (root, StringValue ("Logo"));
ret = DataUrlHelper.FileToDataUrl (logopath);
if (!string.IsNullOrWhiteSpace (ret)) return ret;
return String.Empty;
}
}
public string Publisher { get { return StringResValue ("PublisherDisplayName"); } }
public bool ResourcePackage { get { return BoolValue ("ResourcePackage"); } }
public override object BuildJSON ()
{
return new
{
display_name = DisplayName,
description = Description,
publisher_display_name = Publisher,
Framework = Framework,
resource_package = ResourcePackage,
logo = Logo,
logo_base64 = LogoBase64
};
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class MRApplication: Dictionary<string, string>
{
protected Ref<IntPtr> m_hReader = IntPtr.Zero;
protected Ref<PriReader> m_pri = null;
protected Ref<bool> m_usePri = false;
protected Ref<bool> m_enablePri = false;
protected string m_root = String.Empty;
public MRApplication (ref IntPtr hReader, ref PriReader priBundle, ref bool usePri, ref bool enablePri, string rootDir) : base (StringComparer.OrdinalIgnoreCase)
{
m_hReader = hReader;
m_pri = priBundle;
m_usePri = usePri;
m_enablePri = enablePri;
m_root = rootDir;
}
public MRApplication (ref Ref<IntPtr> m_hReader, ref Ref<PriReader> m_priBundle, ref Ref<bool> m_usePri, ref Ref<bool> m_enablePri, string rootDir)
{
this.m_hReader = m_hReader;
this.m_pri = m_priBundle;
this.m_usePri = m_usePri;
this.m_enablePri = m_enablePri;
this.m_root = rootDir;
}
public string UserModelID { get { return this ["AppUserModelID"]; } }
protected bool EnablePri ()
{
if (m_pri == null || m_pri.Value == null) return false;
if (!m_usePri.Value) return false;
return m_enablePri.Value;
}
protected string StringResValue (string attr)
{
try
{
var res = this [attr];
try
{
if (m_usePri && m_enablePri)
{
if (PriFileHelper.IsMsResourcePrefix (res))
return m_pri.Value.String (res) ?? res;
}
}
catch (Exception) { }
return res;
}
catch (Exception) { return String.Empty; }
}
protected string PriGetRes (string resName)
{
if (string.IsNullOrEmpty (resName)) return string.Empty;
if (m_pri == null || m_pri.Value == null) return string.Empty;
return m_pri.Value.Resource (resName);
}
protected bool IsFilePathKey (string key)
{
foreach (var i in ConstData.FilePathItems)
if ((i?.Trim ()?.ToLower () ?? "") == (key?.Trim ()?.ToLower () ?? ""))
return true;
return false;
}
public new string this [string key]
{
get
{
string value;
if (!TryGetValue (key, out value))
{
value = string.Empty;
base [key] = value;
}
if (!EnablePri ()) return value;
if (PriFileHelper.IsMsResourcePrefix (value))
{
string pri = PriGetRes (value);
return string.IsNullOrEmpty (pri) ? value : pri;
}
if (IsFilePathKey (key) && !string.IsNullOrEmpty (value))
{
string pri = PriGetRes (value);
return string.IsNullOrEmpty (pri) ? value : pri;
}
return value;
}
}
public string At (string key)
{
string value;
if (!TryGetValue (key, out value)) throw new KeyNotFoundException ($"PRBaseApplication.At: key \"{key}\" not found");
if (!EnablePri ()) return value;
if (PriFileHelper.IsMsResourcePrefix (value))
{
string pri = PriGetRes (value);
if (!string.IsNullOrEmpty (pri))
return pri;
}
return value;
}
public string NewAt (string key, bool toPriString)
{
string value;
if (!TryGetValue (key, out value))
{
value = string.Empty;
base [key] = value;
}
if (!EnablePri () && toPriString) return value;
if (PriFileHelper.IsMsResourcePrefix (value))
{
string pri = PriGetRes (value);
return string.IsNullOrEmpty (pri) ? value : pri;
}
if (IsFilePathKey (key) && !string.IsNullOrEmpty (value))
{
string pri = PriGetRes (value);
return string.IsNullOrEmpty (pri) ? value : pri;
}
return value;
}
public string NewAtBase64 (string key)
{
string value = NewAt (key, true);
if (!IsFilePathKey (key) || string.IsNullOrEmpty (value)) return "";
switch (PackageReadHelper.GetPackageType (m_hReader))
{
case 1: // PKGTYPE_APPX
{
var root = m_root;
var logopath = Path.Combine (root, NewAt (key, true));
var ret = DataUrlHelper.FileToDataUrl (logopath);
if (!string.IsNullOrWhiteSpace (ret)) return ret;
logopath = Path.Combine (root, NewAt (key, false));
ret = DataUrlHelper.FileToDataUrl (logopath);
if (!string.IsNullOrWhiteSpace (ret)) return ret;
return String.Empty;
} break;
}
return "";
}
public static bool operator == (MRApplication a, MRApplication b)
{
if (ReferenceEquals (a, b)) return true;
if ((object)a == null || (object)b == null) return false;
return string.Equals (a.UserModelID, b.UserModelID, StringComparison.OrdinalIgnoreCase);
}
public static bool operator != (MRApplication a, MRApplication b)
{
return !(a == b);
}
public override bool Equals (object obj)
{
var other = obj as MRApplication;
if (other == null) return false;
return this == other;
}
public override int GetHashCode ()
{
return (UserModelID ?? "").ToLowerInvariant ().GetHashCode ();
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class MRApplications: BaseInfoSectWithPRISingle, IEnumerable<MRApplication>
{
private IntPtr _hList = IntPtr.Zero;
private List<MRApplication> _apps;
public MRApplications (
ref IntPtr hReader,
ManifestReader reader,
ref PriReader priBundle,
ref bool usePri,
ref bool enablePri)
: base (ref hReader, reader, ref priBundle, ref usePri, ref enablePri)
{
if (IsValid)
{
_hList = PackageReadHelper.GetManifestApplications (m_hReader.Value);
}
}
#region Dispose
public new void Dispose ()
{
if (_hList != IntPtr.Zero)
{
PackageReadHelper.DestroyManifestApplications (_hList);
_hList = IntPtr.Zero;
}
base.Dispose ();
}
~MRApplications ()
{
Dispose ();
}
#endregion
#region Applications
public List<MRApplication> Applications
{
get
{
if (_apps == null)
_apps = ReadApplications ();
return _apps;
}
}
#endregion
#region
public MRApplication this [int index]
{
get { return Applications [index]; }
}
public MRApplication this [string key]
{
get
{
foreach (var app in Applications)
{
if (string.Equals (app.UserModelID, key, StringComparison.OrdinalIgnoreCase))
{
return app;
}
}
return null;
}
}
#endregion
#region IEnumerable
public IEnumerator<MRApplication> GetEnumerator ()
{
return Applications.GetEnumerator ();
}
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
#endregion
#region C++ get
private List<MRApplication> ReadApplications ()
{
var list = new List<MRApplication> ();
if (_hList == IntPtr.Zero) return list;
IntPtr hMapList = PackageReadHelper.ApplicationsToMap (_hList);
if (hMapList == IntPtr.Zero) return list;
try
{
uint count = (uint)Marshal.ReadInt32 (hMapList);
int baseOffset = Marshal.SizeOf (typeof (uint));
for (int i = 0; i < count; i++)
{
IntPtr hKeyValues = Marshal.ReadIntPtr (hMapList, baseOffset + i * IntPtr.Size);
if (hKeyValues == IntPtr.Zero) continue;
list.Add (ReadSingleApplication (hKeyValues));
}
}
finally
{
PackageReadHelper.DestroyApplicationsMap (hMapList);
}
return list;
}
private MRApplication ReadSingleApplication (IntPtr hKeyValues)
{
var app = new MRApplication (ref m_hReader, ref m_pri, ref m_usePri, ref m_enablePri, m_reader.Value.FileRoot);
uint pairCount = (uint)Marshal.ReadInt32 (hKeyValues);
int baseOffset = Marshal.SizeOf (typeof (uint));
int pairSize = Marshal.SizeOf (typeof (PackageReadHelper.PAIR_PVOID));
for (int j = 0; j < pairCount; j++)
{
IntPtr pPair = IntPtr.Add (hKeyValues, baseOffset + j * pairSize);
var pair = (PackageReadHelper.PAIR_PVOID)Marshal.PtrToStructure (pPair, typeof (PackageReadHelper.PAIR_PVOID));
if (pair.lpKey == IntPtr.Zero) continue;
string key = Marshal.PtrToStringUni (pair.lpKey);
if (string.IsNullOrEmpty (key)) continue;
string value = pair.lpValue != IntPtr.Zero
? Marshal.PtrToStringUni (pair.lpValue)
: string.Empty;
app.Add (key, value);
}
return app;
}
#endregion
public override object BuildJSON ()
{
using (var apps = this)
{
return apps.Select (app => {
var dict = new Dictionary<string, object> (StringComparer.OrdinalIgnoreCase);
foreach (var kv in app)
{
dict [kv.Key] = kv.Value;
if (ConstData.IsFilePathKey (kv.Key))
{
dict [(kv.Key?.Trim () ?? "") + "_Base64"] = app.NewAtBase64 (kv.Key);
}
}
dict ["AppUserModelID"] = app.UserModelID;
return dict;
}).ToList ();
}
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class MRCapabilities: BaseInfoSection, ICapabilities
{
public MRCapabilities (ref IntPtr hReader) : base (ref hReader) { }
public List<string> Capabilities
{
get
{
var ret = new List<string> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetCapabilitiesList (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
uint count = (uint)Marshal.ReadInt32 (hList);
int baseOffset = Marshal.SizeOf (typeof (uint)); // dwSize 后
for (int i = 0; i < count; i++)
{
IntPtr pStr = Marshal.ReadIntPtr (hList, baseOffset + i * IntPtr.Size);
if (pStr == IntPtr.Zero) continue;
string s = Marshal.PtrToStringUni (pStr);
if (!string.IsNullOrEmpty (s)) ret.Add (s);
}
}
finally
{
PackageReadHelper.DestroyWStringList (hList);
}
return ret;
}
}
public List<string> DeviceCapabilities
{
get
{
var ret = new List<string> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetDeviceCapabilitiesList (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
uint count = (uint)Marshal.ReadInt32 (hList);
int baseOffset = Marshal.SizeOf (typeof (uint)); // dwSize 后
for (int i = 0; i < count; i++)
{
IntPtr pStr = Marshal.ReadIntPtr (hList, baseOffset + i * IntPtr.Size);
if (pStr == IntPtr.Zero) continue;
string s = Marshal.PtrToStringUni (pStr);
if (!string.IsNullOrEmpty (s)) ret.Add (s);
}
}
finally
{
PackageReadHelper.DestroyWStringList (hList);
}
return ret;
}
}
public List<string> CapabilityDisplayNames
{
get
{
var caps = Capabilities;
var dev = DeviceCapabilities;
var ret = new List<string> ();
foreach (var c in caps)
{
var capname = CacheData.GetPackageCapabilityDisplayName (c);
if (String.IsNullOrWhiteSpace (capname)) ret.Add (c);
else ret.Add (capname);
}
foreach (var d in dev)
{
var dcapname = CacheData.GetPackageCapabilityDisplayName (d);
if (!String.IsNullOrWhiteSpace (dcapname)) ret.Add (dcapname);
}
return ret;
}
}
public override object BuildJSON ()
{
return new
{
capabilities_name = Capabilities,
device_capabilities = DeviceCapabilities,
scales = CapabilityDisplayNames
};
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class MRDependencies: BaseInfoSection, IEnumerable<DependencyInfo>
{
public MRDependencies (ref IntPtr hReader) : base (ref hReader) { }
public List<DependencyInfo> Dependencies
{
get
{
var output = new List<DependencyInfo> ();
if (!IsValid) return output;
IntPtr hList = PackageReadHelper.GetDependencesInfoList (m_hReader);
if (hList == IntPtr.Zero) return output;
try
{
var deps = PackageReadHelper.ReadDependencyInfoList (hList);
foreach (var dep in deps)
{
// dep.lpName / dep.lpPublisher 是 IntPtr
string name = Marshal.PtrToStringUni (dep.lpName) ?? "";
string publisher = Marshal.PtrToStringUni (dep.lpPublisher) ?? "";
// VERSION 直接映射为 System.Version
var ver = new DataUtils.Version (dep.verMin.major, dep.verMin.minor, dep.verMin.build, dep.verMin.revision);
output.Add (new DependencyInfo (name, publisher, ver));
}
}
finally
{
PackageReadHelper.DestroyDependencesInfoList (hList);
}
return output;
}
}
public DependencyInfo this [int index] => Dependencies [index];
public IEnumerator<DependencyInfo> GetEnumerator ()
{
return Dependencies.GetEnumerator ();
}
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
public override object BuildJSON ()
{
return this.Select (d => new {
name = d.Name,
publisher = d.Publisher,
vermin = d.Version.BuildJSON ()
}).ToList ();
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class MRResources: BaseInfoSection, IResources
{
public MRResources (ref IntPtr hReader) : base (ref hReader) { }
public List<DXFeatureLevel> DXFeatures
{
get
{
var ret = new List<DXFeatureLevel> ();
try
{
var dw = PackageReadHelper.GetResourcesDxFeatureLevels (m_hReader);
if ((dw & 0x1) != 0) ret.Add (DXFeatureLevel.Level9);
if ((dw & 0x2) != 0) ret.Add (DXFeatureLevel.Level10);
if ((dw & 0x4) != 0) ret.Add (DXFeatureLevel.Level11);
if ((dw & 0x8) != 0) ret.Add (DXFeatureLevel.Level12);
}
catch (Exception) { }
return ret;
}
}
public List<string> Languages
{
get
{
var ret = new List<string> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetResourcesLanguages (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
ret = PackageReadHelper.ReadWStringList (hList).ToList ();
}
finally
{
PackageReadHelper.DestroyWStringList (hList);
}
return ret;
}
}
public List<int> Languages_LCID
{
get
{
var ret = new List<int> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetResourcesLanguagesToLcid (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
ret = PackageReadHelper.ReadLcidList (hList).ToList ();
}
finally
{
PackageReadHelper.DestroyResourcesLanguagesLcidList (hList);
}
return ret;
}
}
public List<int> Scales
{
get
{
var ret = new List<int> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetResourcesLanguagesToLcid (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
ret = PackageReadHelper.ReadUInt32List (hList).Select (e => (int)e).ToList ();
}
finally
{
PackageReadHelper.DestroyUInt32List (hList);
}
return ret;
}
}
public override object BuildJSON ()
{
return new
{
dx_feature_levels = DXFeatures.Select (e => (int)e).ToList (),
languages = Languages,
scales = Scales
};
}
}
public class MRPrerequisites: BaseInfoSection, IPrerequisites
{
public MRPrerequisites (ref IntPtr hReader) : base (ref hReader) { }
protected DataUtils.Version GetVersion (string name)
{
PackageReadHelper.VERSION ver;
bool res = PackageReadHelper.GetManifestPrerequisite (m_hReader, name, out ver);
if (res) return new DataUtils.Version (ver.major, ver.minor, ver.build, ver.revision);
else return new DataUtils.Version ();
}
protected string GetVersionDescription (string name)
{
var ptr = PackageReadHelper.GetPackagePrerequistieSystemVersionName (m_hReader, name);
return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? "";
}
public string OSMaxVersionDescription { get { return GetVersionDescription ("OSMaxVersionTested"); } }
public DataUtils.Version OSMaxVersionTested { get { return GetVersion ("OSMaxVersionTested"); } }
public DataUtils.Version OSMinVersion { get { return GetVersion ("OSMinVersion"); } }
public string OSMinVersionDescription { get { return GetVersionDescription ("OSMinVersion"); } }
public override object BuildJSON ()
{
return new
{
os_min_version = OSMinVersion.BuildJSON (),
os_min_version_description = OSMinVersionDescription,
os_max_version_tested = OSMaxVersionTested.BuildJSON (),
os_max_version_tested_description = OSMaxVersionDescription
};
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class ManifestReader: IDisposable
{
private IntPtr m_hReader = PackageReadHelper.CreateManifestReader ();
private string m_filePath = string.Empty;
private bool m_usePRI = false;
private bool m_enablePRI = false;
private PriReader m_pri = new PriReader ();
public IntPtr Instance => m_hReader;
public string FileRoot{ get { return Path.GetPathRoot (m_filePath); } }
private void InitPri ()
{
m_pri.Dispose ();
if (!m_usePRI) return;
#region Get PRI IStream
switch (Type)
{
case PackageType.Appx:
{
var pripath = Path.Combine (FileRoot, "resources.pri");
m_pri.Create (pripath);
}
break;
}
#endregion
try
{
var resnames = new HashSet<string> ();
using (var prop = Properties)
{
var temp = prop.Description;
if (PriFileHelper.IsMsResourcePrefix (temp)) resnames.Add (temp);
temp = prop.DisplayName;
if (PriFileHelper.IsMsResourcePrefix (temp)) resnames.Add (temp);
temp = prop.Publisher;
if (PriFileHelper.IsMsResourcePrefix (temp)) resnames.Add (temp);
resnames.Add (prop.Logo);
}
using (var apps = Applications)
{
foreach (var app in apps)
{
foreach (var pair in app)
{
foreach (var pathres in ConstData.FilePathItems)
{
if ((pathres?.Trim ()?.ToLower () ?? "") == (pair.Key?.Trim ()?.ToLower ()))
{
resnames.Add (pair.Value);
}
else if (PriFileHelper.IsMsResourcePrefix (pair.Value))
resnames.Add (pair.Value);
}
}
}
}
m_pri.AddSearch (resnames);
}
catch (Exception) { }
}
public PackageType Type
{
get
{
var value = PackageReadHelper.GetManifestType (m_hReader);
switch (value)
{
case 0: return PackageType.Unknown;
case 1: return PackageType.Appx;
case 2: return PackageType.Bundle;
}
return PackageType.Unknown;
}
}
public PackageRole Role
{
get
{
var value = PackageReadHelper.GetManifestRole (m_hReader);
switch (value)
{
case 0: return PackageRole.Unknown;
case 1: return PackageRole.Application;
case 2: return PackageRole.Framework;
case 3: return PackageRole.Resource;
}
return PackageRole.Unknown;
}
}
public bool IsApplicationManifest { get { return Role == PackageRole.Application; } }
public bool IsValid { get { return m_hReader != IntPtr.Zero && Type != PackageType.Unknown; } }
/// <summary>使用 PRI启用后会预先处理 PRI 文件。</summary>
public bool UsePri { get { return m_usePRI; } set { m_usePRI = value; InitPri (); } }
/// <summary>允许 PRI启用后会返回读取的 PRI 文件结果,需保证 UsePri 开启。</summary>
public bool EnablePri { get { return m_enablePRI; } set { m_enablePRI = value; } }
public MRIdentity Identity { get { return new MRIdentity (ref m_hReader); } }
public MRProperties Properties { get { return new MRProperties (ref m_hReader, this, ref m_pri, ref m_usePRI, ref m_enablePRI); } }
public MRPrerequisites Prerequisites { get { return new MRPrerequisites (ref m_hReader); } }
public MRResources Resources { get { return new MRResources (ref m_hReader); } }
public MRApplications Applications { get { return new MRApplications (ref m_hReader, this, ref m_pri, ref m_usePRI, ref m_enablePRI); } }
public MRCapabilities Capabilities { get { return new MRCapabilities (ref m_hReader); } }
public MRDependencies Dependencies { get { return new MRDependencies (ref m_hReader); } }
public void Dispose ()
{
if (m_hReader != IntPtr.Zero)
{
PackageReadHelper.DestroyManifestReader (m_hReader);
m_hReader = IntPtr.Zero;
}
var lastvalue = m_usePRI;
m_usePRI = false;
InitPri ();
m_usePRI = lastvalue;
}
~ManifestReader () { Dispose (); }
public string FilePath
{
get
{
return m_filePath;
}
set
{
PackageReadHelper.LoadManifestFromFile (m_hReader, m_filePath = value);
}
}
public ManifestReader (string filePath) { FilePath = filePath; }
public ManifestReader () { }
public string JSONText { get { return BuildJsonText (); } }
public string BuildJsonText ()
{
var obj = BuildJsonObject ();
return Newtonsoft.Json.JsonConvert.SerializeObject (
obj,
Newtonsoft.Json.Formatting.Indented
);
}
private object BuildJsonObject ()
{
return new
{
valid = IsValid,
filepath = FilePath,
type = (int)Type,
role = (int)Role,
identity = Identity.BuildJSON (),
properties = Properties.BuildJSON (),
prerequisites = Prerequisites.BuildJSON (),
resources = Resources.BuildJSON (),
capabilities = Capabilities.BuildJSON (),
dependencies = Dependencies.BuildJSON (),
applications = Applications.BuildJSON ()
};
}
}
}