Files
UnrealEngineUWP/Engine/Source/Programs/UnrealBuildTool/System/VCSolutionOptions.cs
2014-03-14 14:13:41 -04:00

318 lines
9.0 KiB
C#

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
namespace UnrealBuildTool
{
public class VCBinarySetting
{
public enum ValueType
{
Bool = 3,
String = 8,
}
public string Name;
public ValueType Type;
public bool BoolValue;
public string StringValue;
public VCBinarySetting()
{
}
public VCBinarySetting(string InName, bool InValue)
{
Name = InName;
Type = ValueType.Bool;
BoolValue = InValue;
}
public VCBinarySetting(string InName, string InValue)
{
Name = InName;
Type = ValueType.String;
StringValue = InValue;
}
public static VCBinarySetting Read(BinaryReader Reader)
{
VCBinarySetting Setting = new VCBinarySetting();
// Read the key
Setting.Name = new string(Reader.ReadChars(Reader.ReadInt32())).TrimEnd('\0');
// Read an equals sign
if (Reader.ReadChar() != '=')
{
throw new InvalidDataException("Expected equals symbol");
}
// Read the value
Setting.Type = (ValueType)Reader.ReadUInt16();
if (Setting.Type == ValueType.Bool)
{
Setting.BoolValue = (Reader.ReadUInt32() != 0);
}
else if (Setting.Type == ValueType.String)
{
Setting.StringValue = new string(Reader.ReadChars(Reader.ReadInt32()));
}
else
{
throw new InvalidDataException("Unknown value type");
}
// Read a semicolon
if (Reader.ReadChar() != ';')
{
throw new InvalidDataException("Expected semicolon");
}
return Setting;
}
public void Write(BinaryWriter Writer)
{
// Write the name
Writer.Write(Name.Length + 1);
Writer.Write(Name.ToCharArray());
Writer.Write('\0');
// Write an equals sign
Writer.Write('=');
// Write the value type
Writer.Write((ushort)Type);
if (Type == ValueType.Bool)
{
Writer.Write(BoolValue ? (uint)0xffff0000 : 0);
}
else if (Type == ValueType.String)
{
Writer.Write(StringValue.Length);
Writer.Write(StringValue.ToCharArray());
}
else
{
throw new InvalidDataException("Unknown value type");
}
// Write a semicolon
Writer.Write(';');
}
public override string ToString()
{
switch (Type)
{
case ValueType.Bool:
return String.Format("{0} = {1}", Name, BoolValue);
case ValueType.String:
return String.Format("{0} = {1}", Name, StringValue);
}
return String.Format("{0} = ???", Name);
}
}
class VCSolutionOptions
{
[Flags]
enum STGC : int
{
Default = 0,
Overwrite = 1,
OnlyIfCurrent = 2,
DangerouslyCommitMerelyToDiskCache = 4,
Consolidate = 8,
}
[Flags]
public enum STGM : int
{
Direct = 0x00000000,
Transacted = 0x00010000,
Simple = 0x08000000,
Read = 0x00000000,
Write = 0x00000001,
ReadWrite = 0x00000002,
ShareDenyNone = 0x00000040,
ShareDenyRead = 0x00000030,
ShareDenyWrite = 0x00000020,
ShareExclusive = 0x00000010,
Priority = 0x00040000,
DeleteOnRelease = 0x04000000,
NoScratch = 0x00100000,
Create = 0x00001000,
Convert = 0x00020000,
FailIfThere = 0x00000000,
NoSnapshot = 0x00200000,
DirectSWMR = 0x00400000,
}
[ComImport, Guid("0000000c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleStream
{
void Read([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, uint cb, out uint pcbRead);
void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, uint cb, out uint pcbWritten);
void Seek(long dlibMove, uint dwOrigin, out long plibNewPosition);
void SetSize(long libNewSize);
void CopyTo(IOleStream pstm, long cb, out long pcbRead, out long pcbWritten);
void Commit(STGC grfCommitFlags);
void Revert();
void LockRegion(long libOffset, long cb, uint dwLockType);
void UnlockRegion(long libOffset, long cb, uint dwLockType);
void Stat(out STATSTG pstatstg, uint grfStatFlag);
void Clone(out IOleStream ppstm);
}
[ComImport, Guid("0000000b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleStorage
{
void CreateStream(string pwcsName, STGM grfMode, uint reserved1, uint reserved2, out IOleStream ppstm);
void OpenStream(string pwcsName, IntPtr reserved1, STGM grfMode, uint reserved2, out IOleStream ppstm);
void CreateStorage(string pwcsName, STGM grfMode, uint reserved1, uint reserved2, out IOleStorage ppstg);
void OpenStorage(string pwcsName, IOleStorage pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved, out IOleStorage ppstg);
void CopyTo(uint ciidExclude, Guid rgiidExclude, IntPtr snbExclude, IOleStorage pstgDest);
void MoveElementTo(string pwcsName, IOleStorage pstgDest, string pwcsNewName, uint grfFlags);
void Commit(STGC grfCommitFlags);
void Revert();
void EnumElements(uint reserved1, IntPtr reserved2, uint reserved3, out IOleEnumSTATSTG ppenum);
void DestroyElement(string pwcsName);
void RenameElement(string pwcsOldName, string pwcsNewName);
void SetElementTimes(string pwcsName, FILETIME pctime, FILETIME patime, FILETIME pmtime);
void SetClass(Guid clsid);
void SetStateBits(uint grfStateBits, uint grfMask);
void Stat(out STATSTG pstatstg, uint grfStatFlag);
}
[ComImport, Guid("0000000d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleEnumSTATSTG
{
void Next(uint celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] STATSTG[] rgelt, out uint pceltFetched);
void RemoteNext(uint celt, [Out, MarshalAs(UnmanagedType.LPArray)] STATSTG[] rgelt, out uint pceltFetched);
void Skip(out uint celt);
void Reset();
void Clone(out IOleEnumSTATSTG ppenum);
}
[DllImport("ole32.dll")]
static extern int StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)]string pwcsName, STGM grfMode, uint reserved, out IOleStorage ppstgOpen);
[DllImport("ole32.dll")]
static extern int StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, IOleStorage pstgPriority, STGM grfMode, IntPtr snbExclude, uint reserved, out IOleStorage ppstgOpen);
public List<VCBinarySetting> SolutionConfiguration = new List<VCBinarySetting>();
public VCSolutionOptions()
{
}
public static VCSolutionOptions Read(string InputFileName)
{
IOleStorage Storage = null;
StgOpenStorage(InputFileName, null, STGM.Direct | STGM.Read | STGM.ShareExclusive, IntPtr.Zero, 0, out Storage);
try
{
IOleEnumSTATSTG Enumerator = null;
Storage.EnumElements(0, IntPtr.Zero, 0, out Enumerator);
try
{
uint Fetched;
STATSTG[] Stats = new STATSTG[200];
Enumerator.Next((uint)Stats.Length, Stats, out Fetched);
VCSolutionOptions Options = new VCSolutionOptions();
foreach (STATSTG Stat in Stats)
{
if (Stat.pwcsName == "SolutionConfiguration")
{
IOleStream OleStream;
Storage.OpenStream(Stat.pwcsName, IntPtr.Zero, STGM.Read | STGM.ShareExclusive, 0, out OleStream);
try
{
uint SizeRead;
byte[] Buffer = new byte[Stat.cbSize];
OleStream.Read(Buffer, (uint)Stat.cbSize, out SizeRead);
using (MemoryStream InputStream = new MemoryStream(Buffer, false))
{
BinaryReader Reader = new BinaryReader(InputStream, Encoding.Unicode);
while (InputStream.Position < InputStream.Length)
{
Options.SolutionConfiguration.Add(VCBinarySetting.Read(Reader));
}
}
}
finally
{
Marshal.ReleaseComObject(OleStream);
}
}
}
return Options;
}
finally
{
Marshal.ReleaseComObject(Enumerator);
}
}
finally
{
Marshal.ReleaseComObject(Storage);
}
}
public void Write(string OutputFileName)
{
IOleStorage OleStorage = null;
StgCreateDocfile(OutputFileName, STGM.Direct | STGM.Create | STGM.Write | STGM.ShareExclusive, 0, out OleStorage);
try
{
if (SolutionConfiguration.Count > 0)
{
using (MemoryStream OutputStream = new MemoryStream())
{
// Write all the settings to the memory stream
BinaryWriter Writer = new BinaryWriter(OutputStream, Encoding.Unicode);
foreach (VCBinarySetting Setting in SolutionConfiguration)
{
Setting.Write(Writer);
}
// Create a named stream in the compound document and write the binary data out
IOleStream OleStream = null;
OleStorage.CreateStream("SolutionConfiguration", STGM.Write | STGM.ShareExclusive, 0, 0, out OleStream);
try
{
uint Written;
OleStream.Write(OutputStream.GetBuffer(), (uint)OutputStream.Length, out Written);
OleStream.Commit(STGC.Overwrite);
}
finally
{
Marshal.ReleaseComObject(OleStream);
}
}
}
}
finally
{
Marshal.ReleaseComObject(OleStorage);
}
}
}
}