/// <nodoc /> public static Possible <ObservedPathSet, DeserializeFailure> TryDeserialize( PathTable pathTable, BuildXLReader reader, PathExpander pathExpander = null, Func <BuildXLReader, AbsolutePath> pathReader = null, Func <BuildXLReader, StringId> stringReader = null) { PathTable.ExpandedAbsolutePathComparer comparer = pathTable.ExpandedPathComparer; int pathCount = reader.ReadInt32Compact(); ObservedPathEntry[] paths = new ObservedPathEntry[pathCount]; string lastStr = null; AbsolutePath lastPath = default(AbsolutePath); for (int i = 0; i < pathCount; i++) { var flags = (ObservedPathEntryFlags)reader.ReadByte(); string enumeratePatternRegex = null; if ((flags & ObservedPathEntryFlags.DirectoryEnumerationWithCustomPattern) != 0) { enumeratePatternRegex = reader.ReadString(); } else if ((flags & ObservedPathEntryFlags.DirectoryEnumerationWithAllPattern) != 0) { enumeratePatternRegex = RegexDirectoryMembershipFilter.AllowAllRegex; } AbsolutePath newPath; string full = null; if (pathReader != null) { newPath = pathReader(reader); } else { int reuseCount = reader.ReadInt32Compact(); if (reuseCount == 0) { full = reader.ReadString(); } else { if (lastStr == null || lastStr.Length < reuseCount) { // This path set is invalid. return(new DeserializeFailure($"Invalid reuseCount: {reuseCount}; last: '{lastStr}', last string length: {lastStr?.Length}")); } string partial = reader.ReadString(); full = lastStr.Substring(0, reuseCount) + partial; } if (!AbsolutePath.TryCreate(pathTable, full, out newPath)) { // It might be failed due to the tokenized path. if (pathExpander == null || !pathExpander.TryCreatePath(pathTable, full, out newPath)) { return(new DeserializeFailure($"Invalid path: '{full}'")); } } } paths[i] = new ObservedPathEntry(newPath, flags, enumeratePatternRegex); if (lastPath.IsValid) { #if DEBUG if (comparer.Compare(lastPath, newPath) >= 0) { return(new DeserializeFailure($"Paths not sorted: " + $"old = '{lastPath.ToString(pathTable)}', new = '{newPath.ToString(pathTable)}';" + $"old str = '{lastStr}', new str = '{full}'")); } #endif } lastPath = newPath; lastStr = full; } int fileNameCount = reader.ReadInt32Compact(); StringId[] fileNames = new StringId[fileNameCount]; for (int i = 0; i < fileNameCount; i++) { fileNames[i] = stringReader?.Invoke(reader) ?? StringId.Create(pathTable.StringTable, reader.ReadString()); } // Read unsafe options var unsafeOptions = UnsafeOptions.TryDeserialize(reader); if (unsafeOptions == null) { return(new DeserializeFailure("UnsafeOptions are null")); } // Note that we validated sort order above. return(new ObservedPathSet( SortedReadOnlyArray <ObservedPathEntry, ObservedPathEntryExpandedPathComparer> .FromSortedArrayUnsafe( ReadOnlyArray <ObservedPathEntry> .FromWithoutCopy(paths), new ObservedPathEntryExpandedPathComparer(comparer)), SortedReadOnlyArray <StringId, CaseInsensitiveStringIdComparer> .FromSortedArrayUnsafe( ReadOnlyArray <StringId> .FromWithoutCopy(fileNames), new CaseInsensitiveStringIdComparer(pathTable.StringTable)), unsafeOptions)); }