You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 2949393 on 2016/04/20 by Graeme.Thornton Orion non-pak file security. - Removed security bypass code from platform pak file - Added a delegate to pak file code which allows the game to decide whether a file should be allowed or not - Added an orion delegate which whitelists appropriate files #rb robert.manuszewski #tests win64 client + dedicated server. golden path. Change 2949232 on 2016/04/19 by david.nikdel #ROBOMERGE-AUTHOR: michael.noland Paragon: Added a distinct menu frame rate limit, currently set to 60 fps and not visible in settings (if the user sets a game frame rate limit of below 60, we also clamp the menu limit to that threshold, so they can go down but not up for menus) #jira OR-18017 #rb marcus.wassmer #tests Ran paragon and switched between gameplay, menus, and replays, observing t.MaxFPS at different points #ROBOMERGE-SOURCE: CL 2949231 in //Orion/Main/... #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2949032 on 2016/04/19 by Zak.Middleton #orion - Lower default NetUpdateFrequency for minions (10->6). Avoid excessive latency for some knockback/knockup abilities that would have noticeable lag by forcing an update sooner when they are triggered. This should have the following effects: 1. Reduce server CPU cost (we tick minions at the net frequency). 2. Reduce server bandwidth 3. Reduce client CPU cost (we move character capsules and perform overlaps when new positions are received). #rb Bart.Bressler, John.Pollard #codereview Dmitry.Rekman #tests MultiPIE AI lane, Replays Change 2948966 on 2016/04/19 by Lina.Halper Added log (check) of the asset info for Anim Per Track contains invalid format key #rb: Michael.Noland #code review: Martin.Wilson, Laurent.Delayen, Michael.Noland #tests: editor/ cooked and test with AI_Tests with 10 bots. Change 2948876 on 2016/04/19 by Michael.Noland PS4: Validate that the texture pool size is not set to automatic (-1, which will crash later on as an attempt to allocate too much memory) #rb none #codereview marcus.wassmer #tests Ran Paragon on PS4 Change 2948765 on 2016/04/19 by Daniel.Lamb Removed AssetImportData tag from cooked asset registry builds. #rb Andrew.Grant #test Cook orion Change 2948691 on 2016/04/19 by Marcus.Wassmer Fix copytoresolvetarget ensure #rb none #test pc agora Change 2948633 on 2016/04/19 by david.nikdel #ROBOMERGE-AUTHOR: jason.bestimt [AUTOMERGE] Fix copytoresolve crash and change validation to ensure. #test PC editor / PC golden path #rb none -------- Integrated using branch //Orion/Main_to_//Orion/Release-Next (reversed) of change#2948169 by Marcus.Wassmer on 2016/04/19 10:50:32. #ROBOMERGE-SOURCE: CL 2948632 in //Orion/Main/... #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2948507 on 2016/04/19 by david.nikdel #ROBOMERGE-AUTHOR: andrew.grant Merging 2937781 (Pak signing) using //Orion/Dev-General_to_Release #rb none #tests cooked client, checked game runs #ROBOMERGE-SOURCE: CL 2948497 in //Orion/Release-0.24.1/... via CL 2948506 #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2948431 on 2016/04/19 by Steve.Robb CL#s 2919775 and 2942793 integrated to prevent annotation map performance problems on shutdown and asserts in PIE. #codereview robert.manuszewski,bob.tellez #rb bob.tellez #tests Ran editor Change 2948408 on 2016/04/19 by Leslie.Nivison Adding .tps #rb none #test none Change 2948185 on 2016/04/19 by david.nikdel #ROBOMERGE-AUTHOR: chris.bunner Fix for HLOD visibility freeze. #tests Golden Path, Editor #rb rolando.caloca, michael.noland #lockdown andrew.grant #jira OR-19863 #ROBOMERGE-SOURCE: CL 2948182 in //Orion/Release-0.24.1/... via CL 2948183 #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2948149 on 2016/04/19 by Simon.Tovey Fixed crash. Collision rendering path was not dealing with mesh batch with 0 triangles where other paths do. #rb none #tests No more crash #codereview Marcus.Wassmer Change 2948129 on 2016/04/19 by Lukasz.Furman fixed gameplay debugger getting stuck with outdated data pack on client, changed names of AI related debug cvars #rb none #tests game, PIE #codereview Mieszko.Zielinski Change 2948027 on 2016/04/19 by david.nikdel #ROBOMERGE-AUTHOR: graeme.thornton Fix for OR-20033 - CRASH: Client will crash with FRCPassPostProcessCircleDOFSetup #rb none #tests checked game runs without crashing #ROBOMERGE-SOURCE: CL 2948017 in //Orion/Main/... #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2947558 on 2016/04/18 by Matt.Kuhlenschmidt Fix compile error #rb none, #tests none Change 2947509 on 2016/04/18 by Matt.Kuhlenschmidt Added more logging to track down https://jira.ol.epicgames.net/browse/OR-19841 #rb none, #tests none Change 2947412 on 2016/04/18 by Ryan.Gerleve Fix shadowed variable. #rb none #tests none Change 2947377 on 2016/04/18 by Jamie.Dale Gather paths are now sorted by fuzzy-ness, so that more specific includes beat less specific excludes #rb Matt.Kuhlenschmidt #tests Built for Windows. Ran a gather, and confirmed that explicitly included heroes were now gathered, and that generically excluded heroes were absent from the gather. Change 2947351 on 2016/04/18 by Ryan.Gerleve Allow overriding the demo.AsyncLoadWorld setting with a URL option when playing a replay. Store the entire URL in the demo net driver instead of just the map name, so that the options can be accessed later. #tests golden path, replays #rb john.pollard Change 2947103 on 2016/04/18 by david.nikdel #ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 24.1 @ CL 2947071 #RB:none #Tests:none #ROBOMERGE-SOURCE: CL 2947102 in //Orion/Main/... #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2947007 on 2016/04/18 by Zak.Middleton #ue4 - Improve linear smoothing in the presence of low net frequency updates. #rb Bart.Bressler #tests MultiPIE AI with lanes Change 2946994 on 2016/04/18 by Mieszko.Zielinski Improvements to NavigationSystem's "abstract navigation data" support #UE4 #rb Lukasz.Furman #test golden path Change 2946760 on 2016/04/18 by Chris.Bunner Fixing up bad merge, recommit of CL 2819472 - ForceLOD now clamps to available LODs on primitive, i.e. use MinLOD rather than not drawing at all. #tests Editor #rb None Change 2946745 on 2016/04/18 by david.nikdel #ROBOMERGE-AUTHOR: jason.bestimt #ORION_MAIN - Merge 24.1 @ CL 2946637 #RB:none #Tests:none #ROBOMERGE-SOURCE: CL 2946656 in //Orion/Main/... #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2946645 on 2016/04/18 by Richard.Fawcett When promoting a buidl to staged, prevent enumeration of files already in S3 Enumerating files in S3 is a slow process, and it turns out that simply uploading all chunks blindly is more efficient than enumerating existing chunks and selectively uploading only the new ones. #rb Leigh.Swift #tests This technique has already been used in launcher promotions for several months Change 2946622 on 2016/04/18 by Richard.Fawcett By default, when enumerating chunks from a manifest file, skip checking they exist on disk at enumeration time. This will fail anyway further down the line if the files don't exist, but will improve speed of stage promotions by around five minutes. In practice, we have NEVER seen a job fail at this point because of the existence check. #rb Leigh.Swift #tests Ensure that output of ExtractDataFilenamesFromManifest method is identical both with and without bSkipExistsCheck specified. Change 2945812 on 2016/04/15 by Daniel.Lamb Fixed error in diff cooked build commandlet. #rb ben.marsh #test Compile. Change 2945110 on 2016/04/15 by Matt.Kuhlenschmidt Fix crash exporting actors with non-scene components to fbx #rb none, #tests full scene exporting on maps that crashed #codereview alexis.matte Change 2945078 on 2016/04/15 by Simon.Tovey Fix for OR-19778 When some pooled systems are reused, on init they have a non zero lod level but the emitter instances are created at LOD 0 initially. So the component did not think it had to update it's LOD but the emitters were not at the correct LOD. Have forced a LOD set on init when the component LOD is non-zero. #rb none #tests Works in editor and game. #codereview Olaf.Piesche Change 2944664 on 2016/04/14 by Uriel.Doyon Fix to SM4 compilation issue #jira OR-19706 #rb marcus.wassmer #tests tested editor in SM4 and SM5 Change 2944642 on 2016/04/14 by Lukasz.Furman changed waypoint switch conditions in meta nav paths #rb none #tests PIE #codereview Mieszko.Zielinski Change 2944599 on 2016/04/14 by david.nikdel #ROBOMERGE-AUTHOR: andrew.grant Added sha1 to UnrealPak list output #rb none #tests listed content of pakfile #ROBOMERGE-SOURCE: CL 2944595 in //Orion/Release-0.24/... via CL 2944597 via CL 2944598 #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2944441 on 2016/04/14 by Marcus.Wassmer Duplicate change to output shader compiler errors. #rb none #test run PC and see errors. Change 2944437 on 2016/04/14 by John.Pollard Possible fix for https://jira.ol.epicgames.net/browse/OR-19614 #rb JoshM #codereview Josh.Markiewicz #tests Golden path matchmaking Change 2944430 on 2016/04/14 by david.nikdel #ROBOMERGE-AUTHOR: michael.noland Engine: Added support for more/fewer settings in individual categories to the editor scalability control widget #rb david.ratti #tests Tested in the editor #ROBOMERGE-SOURCE: CL 2944428 in //Orion/Main/... #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2944198 on 2016/04/14 by David.Ratti Paragon - register for slow/stun/root/silence callbacks on any tag count change, not just add/remove. This is so the UI will update if you get another stack of a stackable slow GE. Ability system - unify client stack count change code path with server. Client now properly update owner ASC's tag map and broadcasts all delegates there. #rb dayY #tests pie Change 2944124 on 2016/04/14 by Wes.Hunt Change the TPS redirects for DX modules to point to the proper DX redist TPS which is what packaged games will need. #codereview:leslie.nivison #rb none #tests ran UAT ListThirdPartySoftware <for Orion> Change 2944107 on 2016/04/14 by Wes.Hunt MeshUtilities now depends on new module nvTessLib to better track the third party dependency. #codereview:daniel.wright #rb none #tests build OrionClient/Editor for Win64 Change 2944102 on 2016/04/14 by Wes.Hunt Tweak to UBT -ListBuildFolders to do a distinct in a better place to cut down on duplicate module searches. #tests ran the UBT command #rb none Change 2943851 on 2016/04/14 by Ryan.Gerleve Fix the ForEachNetDriver helper function to get the world context directly off the world instead of going through the game instance. Ensures the correct net drivers will be used when there are multiple worlds but only one game instance. #rb john.pollard #tests golden path, replays, PIE Change 2943847 on 2016/04/14 by Ryan.Gerleve Fixes to support client replay recording & playback in another world: When recording a replay, only swap actor roles if the remote role is ROLE_Authority When loading a replay checkpoint, call NetworkRemapPath to make sure paths have the correct name in the GuidCache #rb john.pollard #tests golden path, replays, PIE Change 2943691 on 2016/04/14 by david.nikdel #ROBOMERGE-AUTHOR: jason.bestimt #ORION_24 - Fix for OR-19609, OR-19610, and OR-19611 #RB:none #Tests:none #ROBOMERGE-SOURCE: CL 2943687 in //Orion/Release-0.24/... via CL 2943688 #ROBOMERGE-BOT: ORION (Main -> Dev-General) Change 2943508 on 2016/04/14 by Richard.Fawcett Automation: Add support for multipart file uploads to Amazon S3 to increase speed of large file uploads. #jira OPPBUILD-44 #rb Leigh.Swift #tests Uploaded files to S3 using the new routines, downlaoded via AWS management console and ensured downloaded files identical to uploaded ones Change 2943274 on 2016/04/13 by jason.bestimt #ORION_MAIN - Merge 24 @ CL 2943257 #RB:none #Tests:none #ROBOMERGE-SOURCE: CL 2943271 in //Orion/Main/... #ROBOMERGE-BOT: ORION (Main -> Dev-General) #ROBOMERGE-SAYS: Beep boop! I couldn't merge this change. Please do it yourself, human. #CodeReview: david.nikdel, jason.bestimt Change 2943178 on 2016/04/13 by Olaf.Piesche Bumping size of the particle curve texture to 512x512 #rb martin.mittring #tests PC Editor, Game Change 2943174 on 2016/04/13 by Aaron.McLeran OR-19392 Ensure condition failed: (*RequiresInitialization == 0) on loading into PVP match - Removing ensure since there is a rare edge case where it's possible for a sound looping node may get ResetChildren called twice. - Condition is when a child random node o fa looping node has a blank entry and results in no sound chosen in a given frame (which results in ResetChildren getting called). Later in the frame, if a sound had previously been playing with an active sound, it will have stop called on it, which will call NotifyWaveInstanceFinished and hit the ensure. Simply using the branch to check if the looping node has been initialized will work fine in this and other cases. #codereview Bob.Tellez #rb Bob.Tellez #tests ran orion with this change testing problematic sound cue Change 2943042 on 2016/04/13 by Rob.Cannaday Fix crash in HTTP completion delegates on shutdown Stop ticking HTTP retry manager after FOnlineSubsystemImpl::Shutdown has been called #rb josh.markiewicz #tests shutting down multiple times Change 2942913 on 2016/04/13 by Lukasz.Furman added meta navmesh paths #orion #rb Mieszko.Zielinski #tests PIE Change 2942132 on 2016/04/13 by Wes.Hunt Enable UBT -ListBuildFolders to operate on Mac and iOS platforms without having to fully set up the remote environment. #codereview:leslie.nivison #rb peter.sauerbrei #tests running UBT with and without -listbuildfolders Change 2941651 on 2016/04/12 by Jason.Bestimt #ORION_DG - Merge MAIN @ CL 2941645 #RB:none #Tests:none Change 2941539 on 2016/04/12 by Laurent.Delayen FABRIK: Normalize outgoing rotations. Fixes Chains Q ability crashing. #rb none #tests Chains not crashing Change 2941469 on 2016/04/12 by Wes.Hunt Fix UBT -ListBuildFolders to not prep target for deployment. #codereview:leslie.nivison #rb none #tests tested -ListBuildFolders for Android Change 2941434 on 2016/04/12 by Leslie.Nivison Adding/cleaning up .tps files #rb none #test none Change 2941241 on 2016/04/12 by Daniel.Lamb Removed shadername from the shader code to fix deterministic material cooking issue. #jira UE-29320 #codereview Marcus.Wassmer #rb Marcus.Wassmer #test Running editor, cooking orion. Change 2941046 on 2016/04/12 by Laurent.Delayen Added safety net for non state AnimNotifies having a non-zero EndTriggerTimeOffset. Fixes Twinblast double shot for the left primary attack. #rb benn.gallagher #codereview lina.halper, ray.arnett, aaron.eady #tests twinblast's LMB Change 2941032 on 2016/04/12 by Jason.Bestimt #ORION_24 - Merge MAIN @ CL 2940950 #RB:none #Tests:none [CL 2952833 by Andrew Grant in Main branch]
814 lines
26 KiB
C#
814 lines
26 KiB
C#
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace UnrealBuildTool
|
|
{
|
|
/// <summary>
|
|
/// Base class for file system objects (files or directories).
|
|
/// </summary>
|
|
[Serializable]
|
|
public abstract class FileSystemReference
|
|
{
|
|
/// <summary>
|
|
/// The path to this object. Stored as an absolute path, with O/S preferred separator characters, and no trailing slash for directories.
|
|
/// </summary>
|
|
public readonly string FullName;
|
|
|
|
/// <summary>
|
|
/// The canonical full name for this object.
|
|
/// </summary>
|
|
public readonly string CanonicalName;
|
|
|
|
/// <summary>
|
|
/// Constructs a filesystem object for the given path.
|
|
/// </summary>
|
|
public FileSystemReference(string InPath)
|
|
{
|
|
FullName = Path.GetFullPath(InPath).TrimEnd(Path.DirectorySeparatorChar);
|
|
CanonicalName = FullName.ToLowerInvariant();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructs a reference from the given FileSystemInfo.
|
|
/// </summary>
|
|
public FileSystemReference(FileSystemInfo InInfo)
|
|
{
|
|
FullName = InInfo.FullName;
|
|
CanonicalName = FullName.ToLowerInvariant();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Direct constructor for a path
|
|
/// </summary>
|
|
protected FileSystemReference(string InFullName, string InCanonicalName)
|
|
{
|
|
FullName = InFullName;
|
|
CanonicalName = InCanonicalName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a full path by concatenating multiple strings
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
static protected string CombineStrings(DirectoryReference BaseDirectory, params string[] Fragments)
|
|
{
|
|
// Get the initial string to append to, and strip any root directory suffix from it
|
|
StringBuilder NewFullName = new StringBuilder(BaseDirectory.FullName);
|
|
if (NewFullName.Length > 0 && NewFullName[NewFullName.Length - 1] == Path.DirectorySeparatorChar)
|
|
{
|
|
NewFullName.Remove(NewFullName.Length - 1, 1);
|
|
}
|
|
|
|
// Scan through the fragments to append, appending them to a string and updating the base length as we go
|
|
foreach (string Fragment in Fragments)
|
|
{
|
|
// Check if this fragment is an absolute path
|
|
if ((Fragment.Length >= 2 && Fragment[1] == ':') || (Fragment.Length >= 1 && (Fragment[0] == Path.DirectorySeparatorChar || Fragment[0] == Path.AltDirectorySeparatorChar)))
|
|
{
|
|
// It is. Reset the new name to the full version of this path.
|
|
NewFullName.Clear();
|
|
NewFullName.Append(Path.GetFullPath(Fragment).TrimEnd(Path.DirectorySeparatorChar));
|
|
}
|
|
else
|
|
{
|
|
// Append all the parts of this fragment to the end of the existing path.
|
|
int StartIdx = 0;
|
|
while (StartIdx < Fragment.Length)
|
|
{
|
|
// Find the end of this fragment. We may have been passed multiple paths in the same string.
|
|
int EndIdx = StartIdx;
|
|
while (EndIdx < Fragment.Length && Fragment[EndIdx] != Path.DirectorySeparatorChar && Fragment[EndIdx] != Path.AltDirectorySeparatorChar)
|
|
{
|
|
EndIdx++;
|
|
}
|
|
|
|
// Ignore any empty sections, like leading or trailing slashes, and '.' directory references.
|
|
int Length = EndIdx - StartIdx;
|
|
if (Length == 0)
|
|
{
|
|
// Multiple directory separators in a row; illegal.
|
|
throw new ArgumentException("Path fragment '{0}' contains invalid directory separators.");
|
|
}
|
|
else if (Length == 2 && Fragment[StartIdx] == '.' && Fragment[StartIdx + 1] == '.')
|
|
{
|
|
// Remove the last directory name
|
|
for (int SeparatorIdx = NewFullName.Length - 1; SeparatorIdx >= 0; SeparatorIdx--)
|
|
{
|
|
if (NewFullName[SeparatorIdx] == Path.DirectorySeparatorChar)
|
|
{
|
|
NewFullName.Remove(SeparatorIdx, NewFullName.Length - SeparatorIdx);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (Length != 1 || Fragment[StartIdx] != '.')
|
|
{
|
|
// Append this fragment
|
|
NewFullName.Append(Path.DirectorySeparatorChar);
|
|
NewFullName.Append(Fragment, StartIdx, Length);
|
|
}
|
|
|
|
// Move to the next part
|
|
StartIdx = EndIdx + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Append the directory separator
|
|
if (NewFullName.Length == 0 || (NewFullName.Length == 2 && NewFullName[1] == ':'))
|
|
{
|
|
NewFullName.Append(Path.DirectorySeparatorChar);
|
|
}
|
|
|
|
// Set the new path variables
|
|
return NewFullName.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether this name has the given extension.
|
|
/// </summary>
|
|
/// <param name="Extension">The extension to check</param>
|
|
/// <returns>True if this name has the given extension, false otherwise</returns>
|
|
public bool HasExtension(string Extension)
|
|
{
|
|
if (Extension.Length > 0 && Extension[0] != '.')
|
|
{
|
|
return HasExtension("." + Extension);
|
|
}
|
|
else
|
|
{
|
|
return CanonicalName.EndsWith(Extension.ToLowerInvariant());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if the given object is at or under the given directory
|
|
/// </summary>
|
|
/// <param name="Directory"></param>
|
|
/// <returns></returns>
|
|
public bool IsUnderDirectory(DirectoryReference Other)
|
|
{
|
|
return CanonicalName.StartsWith(Other.CanonicalName) && (CanonicalName.Length == Other.CanonicalName.Length || CanonicalName[Other.CanonicalName.Length] == Path.DirectorySeparatorChar);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a relative path from the given base directory
|
|
/// </summary>
|
|
/// <param name="Directory">The directory to create a relative path from</param>
|
|
/// <returns>A relative path from the given directory</returns>
|
|
public string MakeRelativeTo(DirectoryReference Directory)
|
|
{
|
|
// Find how much of the path is common between the two paths. This length does not include a trailing directory separator character.
|
|
int CommonDirectoryLength = -1;
|
|
for (int Idx = 0; ; Idx++)
|
|
{
|
|
if (Idx == CanonicalName.Length)
|
|
{
|
|
// The two paths are identical. Just return the "." character.
|
|
if (Idx == Directory.CanonicalName.Length)
|
|
{
|
|
return ".";
|
|
}
|
|
|
|
// Check if we're finishing on a complete directory name
|
|
if (Directory.CanonicalName[Idx] == Path.DirectorySeparatorChar)
|
|
{
|
|
CommonDirectoryLength = Idx;
|
|
}
|
|
break;
|
|
}
|
|
else if (Idx == Directory.CanonicalName.Length)
|
|
{
|
|
// Check whether the end of the directory name coincides with a boundary for the current name.
|
|
if (CanonicalName[Idx] == Path.DirectorySeparatorChar)
|
|
{
|
|
CommonDirectoryLength = Idx;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Check the two paths match, and bail if they don't. Increase the common directory length if we've reached a separator.
|
|
if (CanonicalName[Idx] != Directory.CanonicalName[Idx])
|
|
{
|
|
break;
|
|
}
|
|
if (CanonicalName[Idx] == Path.DirectorySeparatorChar)
|
|
{
|
|
CommonDirectoryLength = Idx;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there's no relative path, just return the absolute path
|
|
if (CommonDirectoryLength == -1)
|
|
{
|
|
return FullName;
|
|
}
|
|
|
|
// Append all the '..' separators to get back to the common directory, then the rest of the string to reach the target item
|
|
StringBuilder Result = new StringBuilder();
|
|
for (int Idx = CommonDirectoryLength + 1; Idx < Directory.CanonicalName.Length; Idx++)
|
|
{
|
|
// Move up a directory
|
|
Result.Append("..");
|
|
Result.Append(Path.DirectorySeparatorChar);
|
|
|
|
// Scan to the next directory separator
|
|
while (Idx < Directory.CanonicalName.Length && Directory.CanonicalName[Idx] != Path.DirectorySeparatorChar)
|
|
{
|
|
Idx++;
|
|
}
|
|
}
|
|
if (CommonDirectoryLength + 1 < FullName.Length)
|
|
{
|
|
Result.Append(FullName, CommonDirectoryLength + 1, FullName.Length - CommonDirectoryLength - 1);
|
|
}
|
|
return Result.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a string representation of this filesystem object
|
|
/// </summary>
|
|
/// <returns>Full path to the object</returns>
|
|
public override string ToString()
|
|
{
|
|
return FullName;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Representation of an absolute directory path. Allows fast hashing and comparisons.
|
|
/// </summary>
|
|
[Serializable]
|
|
public class DirectoryReference : FileSystemReference, IEquatable<DirectoryReference>
|
|
{
|
|
/// <summary>
|
|
/// Default constructor.
|
|
/// </summary>
|
|
/// <param name="InPath">Path to this directory.</param>
|
|
public DirectoryReference(string InPath)
|
|
: base(InPath)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Construct a DirectoryReference from a DirectoryInfo object.
|
|
/// </summary>
|
|
/// <param name="InInfo">Path to this file</param>
|
|
public DirectoryReference(DirectoryInfo InInfo)
|
|
: base(InInfo)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor for creating a directory object directly from two strings.
|
|
/// </summary>
|
|
/// <param name="InFullName"></param>
|
|
/// <param name="InCanonicalName"></param>
|
|
protected DirectoryReference(string InFullName, string InCanonicalName)
|
|
: base(InFullName, InCanonicalName)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the top level directory name
|
|
/// </summary>
|
|
/// <returns>The name of the directory</returns>
|
|
public string GetDirectoryName()
|
|
{
|
|
return Path.GetFileName(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the directory containing this object
|
|
/// </summary>
|
|
/// <returns>A new directory object representing the directory containing this object</returns>
|
|
public DirectoryReference ParentDirectory
|
|
{
|
|
get
|
|
{
|
|
if (IsRootDirectory())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
int ParentLength = CanonicalName.LastIndexOf(Path.DirectorySeparatorChar);
|
|
if (ParentLength == 2 && CanonicalName[1] == ':')
|
|
{
|
|
ParentLength++;
|
|
}
|
|
|
|
return new DirectoryReference(FullName.Substring(0, ParentLength), CanonicalName.Substring(0, ParentLength));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the parent directory for a file
|
|
/// </summary>
|
|
/// <param name="File">The file to get directory for</param>
|
|
/// <returns>The full directory name containing the given file</returns>
|
|
public static DirectoryReference GetParentDirectory(FileReference File)
|
|
{
|
|
int ParentLength = File.CanonicalName.LastIndexOf(Path.DirectorySeparatorChar);
|
|
return new DirectoryReference(File.FullName.Substring(0, ParentLength), File.CanonicalName.Substring(0, ParentLength));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the directory
|
|
/// </summary>
|
|
public void CreateDirectory()
|
|
{
|
|
Directory.CreateDirectory(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether the directory exists
|
|
/// </summary>
|
|
/// <returns>True if this directory exists</returns>
|
|
public bool Exists()
|
|
{
|
|
return Directory.Exists(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerate files from a given directory
|
|
/// </summary>
|
|
/// <returns>Sequence of file references</returns>
|
|
public IEnumerable<FileReference> EnumerateFileReferences()
|
|
{
|
|
foreach (string FileName in Directory.EnumerateFiles(FullName))
|
|
{
|
|
yield return FileReference.MakeFromNormalizedFullPath(FileName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerate files from a given directory
|
|
/// </summary>
|
|
/// <returns>Sequence of file references</returns>
|
|
public IEnumerable<FileReference> EnumerateFileReferences(string Pattern)
|
|
{
|
|
foreach (string FileName in Directory.EnumerateFiles(FullName, Pattern))
|
|
{
|
|
yield return FileReference.MakeFromNormalizedFullPath(FileName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerate files from a given directory
|
|
/// </summary>
|
|
/// <returns>Sequence of file references</returns>
|
|
public IEnumerable<FileReference> EnumerateFileReferences(string Pattern, SearchOption Option)
|
|
{
|
|
foreach (string FileName in Directory.EnumerateFiles(FullName, Pattern, Option))
|
|
{
|
|
yield return FileReference.MakeFromNormalizedFullPath(FileName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerate subdirectories in a given directory
|
|
/// </summary>
|
|
/// <returns>Sequence of directory references</returns>
|
|
public IEnumerable<DirectoryReference> EnumerateDirectoryReferences()
|
|
{
|
|
foreach (string DirectoryName in Directory.EnumerateDirectories(FullName))
|
|
{
|
|
yield return DirectoryReference.MakeFromNormalizedFullPath(DirectoryName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerate subdirectories in a given directory
|
|
/// </summary>
|
|
/// <returns>Sequence of directory references</returns>
|
|
public IEnumerable<DirectoryReference> EnumerateDirectoryReferences(string Pattern)
|
|
{
|
|
foreach (string DirectoryName in Directory.EnumerateDirectories(FullName, Pattern))
|
|
{
|
|
yield return DirectoryReference.MakeFromNormalizedFullPath(DirectoryName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerate subdirectories in a given directory
|
|
/// </summary>
|
|
/// <returns>Sequence of directory references</returns>
|
|
public IEnumerable<DirectoryReference> EnumerateDirectoryReferences(string Pattern, SearchOption Option)
|
|
{
|
|
foreach (string DirectoryName in Directory.EnumerateDirectories(FullName, Pattern, Option))
|
|
{
|
|
yield return DirectoryReference.MakeFromNormalizedFullPath(DirectoryName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether this path represents a root directory in the filesystem
|
|
/// </summary>
|
|
/// <returns>True if this path is a root directory, false otherwise</returns>
|
|
public bool IsRootDirectory()
|
|
{
|
|
return CanonicalName[CanonicalName.Length - 1] == Path.DirectorySeparatorChar;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Combine several fragments with a base directory, to form a new directory name
|
|
/// </summary>
|
|
/// <param name="BaseDirectory">The base directory</param>
|
|
/// <param name="Fragments">Fragments to combine with the base directory</param>
|
|
/// <returns>The new directory name</returns>
|
|
public static DirectoryReference Combine(DirectoryReference BaseDirectory, params string[] Fragments)
|
|
{
|
|
string FullName = FileSystemReference.CombineStrings(BaseDirectory, Fragments);
|
|
return new DirectoryReference(FullName, FullName.ToLowerInvariant());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two filesystem object names for equality. Uses the canonical name representation, not the display name representation.
|
|
/// </summary>
|
|
/// <param name="A">First object to compare.</param>
|
|
/// <param name="B">Second object to compare.</param>
|
|
/// <returns>True if the names represent the same object, false otherwise</returns>
|
|
public static bool operator ==(DirectoryReference A, DirectoryReference B)
|
|
{
|
|
if ((object)A == null)
|
|
{
|
|
return (object)B == null;
|
|
}
|
|
else
|
|
{
|
|
return (object)B != null && A.CanonicalName == B.CanonicalName;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two filesystem object names for inequality. Uses the canonical name representation, not the display name representation.
|
|
/// </summary>
|
|
/// <param name="A">First object to compare.</param>
|
|
/// <param name="B">Second object to compare.</param>
|
|
/// <returns>False if the names represent the same object, true otherwise</returns>
|
|
public static bool operator !=(DirectoryReference A, DirectoryReference B)
|
|
{
|
|
return !(A == B);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares against another object for equality.
|
|
/// </summary>
|
|
/// <param name="Obj">other instance to compare.</param>
|
|
/// <returns>True if the names represent the same object, false otherwise</returns>
|
|
public override bool Equals(object Obj)
|
|
{
|
|
return (Obj is DirectoryReference) && ((DirectoryReference)Obj) == this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares against another object for equality.
|
|
/// </summary>
|
|
/// <param name="Obj">other instance to compare.</param>
|
|
/// <returns>True if the names represent the same object, false otherwise</returns>
|
|
public bool Equals(DirectoryReference Obj)
|
|
{
|
|
return Obj == this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a hash code for this object
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override int GetHashCode()
|
|
{
|
|
return CanonicalName.GetHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper function to create a remote directory reference. Unlike normal DirectoryReference objects, these aren't converted to a full path in the local filesystem.
|
|
/// </summary>
|
|
/// <param name="AbsolutePath">The absolute path in the remote file system</param>
|
|
/// <returns>New directory reference</returns>
|
|
public static DirectoryReference MakeRemote(string AbsolutePath)
|
|
{
|
|
return new DirectoryReference(AbsolutePath, AbsolutePath.ToLowerInvariant());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper function to create a directory reference from a raw platform path. The path provided *MUST* be exactly the same as that returned by Path.GetFullPath().
|
|
/// </summary>
|
|
/// <param name="AbsolutePath">The absolute path in the file system</param>
|
|
/// <returns>New file reference</returns>
|
|
public static DirectoryReference MakeFromNormalizedFullPath(string AbsolutePath)
|
|
{
|
|
return new DirectoryReference(AbsolutePath, AbsolutePath.ToLowerInvariant());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the parent directory for a file, or returns null if it's null.
|
|
/// </summary>
|
|
/// <param name="File">The file to create a directory reference for</param>
|
|
/// <returns>The directory containing the file </returns>
|
|
public static DirectoryReference FromFile(FileReference File)
|
|
{
|
|
return (File == null)? null : File.Directory;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Representation of an absolute file path. Allows fast hashing and comparisons.
|
|
/// </summary>
|
|
[Serializable]
|
|
public class FileReference : FileSystemReference, IEquatable<FileReference>
|
|
{
|
|
/// <summary>
|
|
/// Default constructor.
|
|
/// </summary>
|
|
/// <param name="InPath">Path to this file</param>
|
|
public FileReference(string InPath)
|
|
: base(InPath)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Construct a FileReference from a FileInfo object.
|
|
/// </summary>
|
|
/// <param name="InInfo">Path to this file</param>
|
|
public FileReference(FileInfo InInfo)
|
|
: base(InInfo)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Default constructor.
|
|
/// </summary>
|
|
/// <param name="InPath">Path to this file</param>
|
|
protected FileReference(string InFullName, string InCanonicalName)
|
|
: base(InFullName, InCanonicalName)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the file name without path information
|
|
/// </summary>
|
|
/// <returns>A string containing the file name</returns>
|
|
public string GetFileName()
|
|
{
|
|
return Path.GetFileName(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the file name without path information or an extension
|
|
/// </summary>
|
|
/// <returns>A string containing the file name without an extension</returns>
|
|
public string GetFileNameWithoutExtension()
|
|
{
|
|
return Path.GetFileNameWithoutExtension(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the file name without path or any extensions
|
|
/// </summary>
|
|
/// <returns>A string containing the file name without an extension</returns>
|
|
public string GetFileNameWithoutAnyExtensions()
|
|
{
|
|
int StartIdx = FullName.LastIndexOf(Path.DirectorySeparatorChar) + 1;
|
|
|
|
int EndIdx = FullName.IndexOf('.', StartIdx);
|
|
if (EndIdx < StartIdx)
|
|
{
|
|
return FullName.Substring(StartIdx);
|
|
}
|
|
else
|
|
{
|
|
return FullName.Substring(StartIdx, EndIdx - StartIdx);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the extension for this filename
|
|
/// </summary>
|
|
/// <returns>A string containing the extension of this filename</returns>
|
|
public string GetExtension()
|
|
{
|
|
return Path.GetExtension(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change the file's extension to something else
|
|
/// </summary>
|
|
/// <param name="Extension">The new extension</param>
|
|
/// <returns>A FileReference with the same path and name, but with the new extension</returns>
|
|
public FileReference ChangeExtension(string Extension)
|
|
{
|
|
string NewFullName = Path.ChangeExtension(FullName, Extension);
|
|
return new FileReference(NewFullName, NewFullName.ToLowerInvariant());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the directory containing this file
|
|
/// </summary>
|
|
/// <returns>A new directory object representing the directory containing this object</returns>
|
|
public DirectoryReference Directory
|
|
{
|
|
get { return DirectoryReference.GetParentDirectory(this); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the given filename exists
|
|
/// </summary>
|
|
/// <returns>True if it exists, false otherwise</returns>
|
|
public bool Exists()
|
|
{
|
|
return File.Exists(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes this file
|
|
/// </summary>
|
|
public void Delete()
|
|
{
|
|
File.Delete(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Combine several fragments with a base directory, to form a new filename
|
|
/// </summary>
|
|
/// <param name="BaseDirectory">The base directory</param>
|
|
/// <param name="Fragments">Fragments to combine with the base directory</param>
|
|
/// <returns>The new file name</returns>
|
|
public static FileReference Combine(DirectoryReference BaseDirectory, params string[] Fragments)
|
|
{
|
|
string FullName = FileSystemReference.CombineStrings(BaseDirectory, Fragments);
|
|
return new FileReference(FullName, FullName.ToLowerInvariant());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Append a string to the end of a filename
|
|
/// </summary>
|
|
/// <param name="A">The base file reference</param>
|
|
/// <param name="B">Suffix to be appended</param>
|
|
/// <returns>The new file reference</returns>
|
|
public static FileReference operator +(FileReference A, string B)
|
|
{
|
|
return new FileReference(A.FullName + B, A.CanonicalName + B.ToLowerInvariant());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two filesystem object names for equality. Uses the canonical name representation, not the display name representation.
|
|
/// </summary>
|
|
/// <param name="A">First object to compare.</param>
|
|
/// <param name="B">Second object to compare.</param>
|
|
/// <returns>True if the names represent the same object, false otherwise</returns>
|
|
public static bool operator ==(FileReference A, FileReference B)
|
|
{
|
|
if ((object)A == null)
|
|
{
|
|
return (object)B == null;
|
|
}
|
|
else
|
|
{
|
|
return (object)B != null && A.CanonicalName == B.CanonicalName;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two filesystem object names for inequality. Uses the canonical name representation, not the display name representation.
|
|
/// </summary>
|
|
/// <param name="A">First object to compare.</param>
|
|
/// <param name="B">Second object to compare.</param>
|
|
/// <returns>False if the names represent the same object, true otherwise</returns>
|
|
public static bool operator !=(FileReference A, FileReference B)
|
|
{
|
|
return !(A == B);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares against another object for equality.
|
|
/// </summary>
|
|
/// <param name="Obj">other instance to compare.</param>
|
|
/// <returns>True if the names represent the same object, false otherwise</returns>
|
|
public override bool Equals(object Obj)
|
|
{
|
|
return (Obj is FileReference) && ((FileReference)Obj) == this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares against another object for equality.
|
|
/// </summary>
|
|
/// <param name="Obj">other instance to compare.</param>
|
|
/// <returns>True if the names represent the same object, false otherwise</returns>
|
|
public bool Equals(FileReference Obj)
|
|
{
|
|
return Obj == this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a hash code for this object
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override int GetHashCode()
|
|
{
|
|
return CanonicalName.GetHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper function to create a remote file reference. Unlike normal FileReference objects, these aren't converted to a full path in the local filesystem, but are
|
|
/// left as they are passed in.
|
|
/// </summary>
|
|
/// <param name="AbsolutePath">The absolute path in the remote file system</param>
|
|
/// <returns>New file reference</returns>
|
|
public static FileReference MakeRemote(string AbsolutePath)
|
|
{
|
|
return new FileReference(AbsolutePath, AbsolutePath.ToLowerInvariant());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper function to create a file reference from a raw platform path. The path provided *MUST* be exactly the same as that returned by Path.GetFullPath().
|
|
/// </summary>
|
|
/// <param name="AbsolutePath">The absolute path in the file system</param>
|
|
/// <returns>New file reference</returns>
|
|
public static FileReference MakeFromNormalizedFullPath(string AbsolutePath)
|
|
{
|
|
return new FileReference(AbsolutePath, AbsolutePath.ToLowerInvariant());
|
|
}
|
|
}
|
|
|
|
static class FileReferenceExtensionMethods
|
|
{
|
|
/// <summary>
|
|
/// Manually serialize a file reference to a binary stream.
|
|
/// </summary>
|
|
/// <param name="Writer">Binary writer to write to</param>
|
|
public static void Write(this BinaryWriter Writer, FileReference File)
|
|
{
|
|
Writer.Write((File == null) ? String.Empty : File.FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serializes a file reference, using a lookup table to avoid serializing the same name more than once.
|
|
/// </summary>
|
|
/// <param name="Writer">The writer to save this reference to</param>
|
|
/// <param name="File">A file reference to output; may be null</param>
|
|
/// <param name="FileToUniqueId">A lookup table that caches previous files that have been output, and maps them to unique id's.</param>
|
|
public static void Write(this BinaryWriter Writer, FileReference File, Dictionary<FileReference, int> FileToUniqueId)
|
|
{
|
|
int UniqueId;
|
|
if (File == null)
|
|
{
|
|
Writer.Write(-1);
|
|
}
|
|
else if (FileToUniqueId.TryGetValue(File, out UniqueId))
|
|
{
|
|
Writer.Write(UniqueId);
|
|
}
|
|
else
|
|
{
|
|
Writer.Write(FileToUniqueId.Count);
|
|
Writer.Write(File);
|
|
FileToUniqueId.Add(File, FileToUniqueId.Count);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Manually deserialize a file reference from a binary stream.
|
|
/// </summary>
|
|
/// <param name="Reader">Binary reader to read from</param>
|
|
/// <returns>New FileReference object</returns>
|
|
public static FileReference ReadFileReference(this BinaryReader Reader)
|
|
{
|
|
string FullName = Reader.ReadString();
|
|
return (FullName.Length == 0) ? null : FileReference.MakeFromNormalizedFullPath(FullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deserializes a file reference, using a lookup table to avoid writing the same name more than once.
|
|
/// </summary>
|
|
/// <param name="Reader">The source to read from</param>
|
|
/// <param name="UniqueFiles">List of previously read file references. The index into this array is used in place of subsequent ocurrences of the file.</param>
|
|
/// <returns>The file reference that was read</returns>
|
|
public static FileReference ReadFileReference(this BinaryReader Reader, List<FileReference> UniqueFiles)
|
|
{
|
|
int UniqueId = Reader.ReadInt32();
|
|
if (UniqueId == -1)
|
|
{
|
|
return null;
|
|
}
|
|
else if (UniqueId < UniqueFiles.Count)
|
|
{
|
|
return UniqueFiles[UniqueId];
|
|
}
|
|
else
|
|
{
|
|
FileReference Result = Reader.ReadFileReference();
|
|
UniqueFiles.Add(Result);
|
|
return Result;
|
|
}
|
|
}
|
|
}
|
|
}
|