public virtual String ReadString() { Contract.Ensures(Contract.Result <String>() != null); if (_stream == null) { __Error.FileNotOpen(); } int currPos = 0; int n; int stringLength; int readLength; int charsRead; // Length of the string in bytes, not chars stringLength = Read7BitEncodedInt(); if (stringLength < 0) { throw new IOException(SR.Format(SR.IO_InvalidStringLen_Len, stringLength)); } if (stringLength == 0) { return(String.Empty); } if (_charBytes == null) { _charBytes = new byte[MaxCharBytesSize]; } if (_charBuffer == null) { _charBuffer = new char[_maxCharsSize]; } StringBuilder sb = null; do { readLength = ((stringLength - currPos) > MaxCharBytesSize) ? MaxCharBytesSize : (stringLength - currPos); n = _stream.Read(_charBytes, 0, readLength); if (n == 0) { __Error.EndOfFile(); } charsRead = _decoder.GetChars(_charBytes, 0, n, _charBuffer, 0); if (currPos == 0 && n == stringLength) { return(new String(_charBuffer, 0, charsRead)); } if (sb == null) { sb = StringBuilderCache.Acquire(stringLength); // Actual string length in chars may be smaller. } sb.Append(_charBuffer, 0, charsRead); currPos += n; } while (currPos < stringLength); return(StringBuilderCache.GetStringAndRelease(sb)); }
private static string GetRelativePath(string relativeTo, string path, StringComparison comparisonType) { if (string.IsNullOrEmpty(relativeTo)) { throw new ArgumentNullException(nameof(relativeTo)); } if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException(nameof(path)); } Debug.Assert(comparisonType == StringComparison.Ordinal || comparisonType == StringComparison.OrdinalIgnoreCase); relativeTo = GetFullPath(relativeTo); path = GetFullPath(path); // Need to check if the roots are different- if they are we need to return the "to" path. if (!PathInternal.AreRootsEqual(relativeTo, path, comparisonType)) { return(path); } int commonLength = PathInternal.GetCommonPathLength(relativeTo, path, ignoreCase: comparisonType == StringComparison.OrdinalIgnoreCase); // If there is nothing in common they can't share the same root, return the "to" path as is. if (commonLength == 0) { return(path); } // Trailing separators aren't significant for comparison int relativeToLength = relativeTo.Length; if (PathInternal.EndsInDirectorySeparator(relativeTo)) { relativeToLength--; } bool pathEndsInSeparator = PathInternal.EndsInDirectorySeparator(path); int pathLength = path.Length; if (pathEndsInSeparator) { pathLength--; } // If we have effectively the same path, return "." if (relativeToLength == pathLength && commonLength >= relativeToLength) { return("."); } // We have the same root, we need to calculate the difference now using the // common Length and Segment count past the length. // // Some examples: // // C:\Foo C:\Bar L3, S1 -> ..\Bar // C:\Foo C:\Foo\Bar L6, S0 -> Bar // C:\Foo\Bar C:\Bar\Bar L3, S2 -> ..\..\Bar\Bar // C:\Foo\Foo C:\Foo\Bar L7, S1 -> ..\Bar StringBuilder sb = StringBuilderCache.Acquire(Math.Max(relativeTo.Length, path.Length)); // Add parent segments for segments past the common on the "from" path if (commonLength < relativeToLength) { sb.Append(PathInternal.ParentDirectoryPrefix); for (int i = commonLength; i < relativeToLength; i++) { if (PathInternal.IsDirectorySeparator(relativeTo[i])) { sb.Append(PathInternal.ParentDirectoryPrefix); } } } else if (PathInternal.IsDirectorySeparator(path[commonLength])) { // No parent segments and we need to eat the initial separator // (C:\Foo C:\Foo\Bar case) commonLength++; } // Now add the rest of the "to" path, adding back the trailing separator int count = pathLength - commonLength; if (pathEndsInSeparator) { count++; } sb.Append(path, commonLength, count); return(StringBuilderCache.GetStringAndRelease(sb)); }
private static string CombineNoChecks(string path1, string path2, string path3, string path4) { if (path1.Length == 0) { return(CombineNoChecks(path2, path3, path4)); } if (path2.Length == 0) { return(CombineNoChecks(path1, path3, path4)); } if (path3.Length == 0) { return(CombineNoChecks(path1, path2, path4)); } if (path4.Length == 0) { return(CombineNoChecks(path1, path2, path3)); } if (IsPathRooted(path4)) { return(path4); } if (IsPathRooted(path3)) { return(CombineNoChecks(path3, path4)); } if (IsPathRooted(path2)) { return(CombineNoChecks(path2, path3, path4)); } bool hasSep1 = PathInternal.IsDirectoryOrVolumeSeparator(path1[path1.Length - 1]); bool hasSep2 = PathInternal.IsDirectoryOrVolumeSeparator(path2[path2.Length - 1]); bool hasSep3 = PathInternal.IsDirectoryOrVolumeSeparator(path3[path3.Length - 1]); if (hasSep1 && hasSep2 && hasSep3) { // Use string.Concat overload that takes four strings return(path1 + path2 + path3 + path4); } else { // string.Concat only has string-based overloads up to four arguments; after that requires allocating // a params string[]. Instead, try to use a cached StringBuilder. StringBuilder sb = StringBuilderCache.Acquire(path1.Length + path2.Length + path3.Length + path4.Length + 3); sb.Append(path1); if (!hasSep1) { sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path2); if (!hasSep2) { sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path3); if (!hasSep3) { sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path4); return(StringBuilderCache.GetStringAndRelease(sb)); } }
public static string Combine(params string[] paths) { if (paths == null) { throw new ArgumentNullException(nameof(paths)); } Contract.EndContractBlock(); int finalSize = 0; int firstComponent = 0; // We have two passes, the first calculates how large a buffer to allocate and does some precondition // checks on the paths passed in. The second actually does the combination. for (int i = 0; i < paths.Length; i++) { if (paths[i] == null) { throw new ArgumentNullException(nameof(paths)); } if (paths[i].Length == 0) { continue; } PathInternal.CheckInvalidPathChars(paths[i]); if (IsPathRooted(paths[i])) { firstComponent = i; finalSize = paths[i].Length; } else { finalSize += paths[i].Length; } char ch = paths[i][paths[i].Length - 1]; if (!PathInternal.IsDirectoryOrVolumeSeparator(ch)) { finalSize++; } } StringBuilder finalPath = StringBuilderCache.Acquire(finalSize); for (int i = firstComponent; i < paths.Length; i++) { if (paths[i].Length == 0) { continue; } if (finalPath.Length == 0) { finalPath.Append(paths[i]); } else { char ch = finalPath[finalPath.Length - 1]; if (!PathInternal.IsDirectoryOrVolumeSeparator(ch)) { finalPath.Append(PathInternal.DirectorySeparatorChar); } finalPath.Append(paths[i]); } } return(StringBuilderCache.GetStringAndRelease(finalPath)); }
/// <summary> /// Try to remove relative segments from the given path (without combining with a root). /// </summary> /// <param name="skip">Skip the specified number of characters before evaluating.</param> private static string RemoveRelativeSegments(string path, int skip = 0) { bool flippedSeparator = false; // Remove "//", "/./", and "/../" from the path by copying each character to the output, // except the ones we're removing, such that the builder contains the normalized path // at the end. var sb = StringBuilderCache.Acquire(path.Length); if (skip > 0) { sb.Append(path, 0, skip); } for (int i = skip; i < path.Length; i++) { char c = path[i]; if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) { // Skip this character if it's a directory separator and if the next character is, too, // e.g. "parent//child" => "parent/child" if (PathInternal.IsDirectorySeparator(path[i + 1])) { continue; } // Skip this character and the next if it's referring to the current directory, // e.g. "parent/./child" =? "parent/child" if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && path[i + 1] == '.') { i++; continue; } // Skip this character and the next two if it's referring to the parent directory, // e.g. "parent/child/../grandchild" => "parent/grandchild" if (i + 2 < path.Length && (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && path[i + 1] == '.' && path[i + 2] == '.') { // Unwind back to the last slash (and if there isn't one, clear out everything). int s; for (s = sb.Length - 1; s >= 0; s--) { if (PathInternal.IsDirectorySeparator(sb[s])) { sb.Length = s; break; } } if (s < 0) { sb.Length = 0; } i += 2; continue; } } // Normalize the directory separator if needed if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) { c = PathInternal.DirectorySeparatorChar; flippedSeparator = true; } sb.Append(c); } if (flippedSeparator || sb.Length != path.Length) { return(StringBuilderCache.GetStringAndRelease(sb)); } else { // We haven't changed the source path, return the original StringBuilderCache.Release(sb); return(path); } }
public virtual string ReadString() { if (_stream == null) { throw new ObjectDisposedException(null, SR.ObjectDisposed_FileClosed); } int currPos = 0; int n; int stringLength; int readLength; int charsRead; // Length of the string in bytes, not chars stringLength = Read7BitEncodedInt(); if (stringLength < 0) { throw new IOException(SR.Format(SR.IO_IO_InvalidStringLen_Len, stringLength)); } if (stringLength == 0) { return(string.Empty); } if (_charBytes == null) { _charBytes = new byte[MaxCharBytesSize]; } if (_charBuffer == null) { _charBuffer = new char[_maxCharsSize]; } StringBuilder sb = null; do { readLength = ((stringLength - currPos) > MaxCharBytesSize) ? MaxCharBytesSize : (stringLength - currPos); n = _stream.Read(_charBytes, 0, readLength); if (n == 0) { throw new EndOfStreamException(SR.IO_EOF_ReadBeyondEOF); } charsRead = _decoder.GetChars(_charBytes, 0, n, _charBuffer, 0); if (currPos == 0 && n == stringLength) { return(new string(_charBuffer, 0, charsRead)); } if (sb == null) { sb = StringBuilderCache.Acquire(stringLength); // Actual string length in chars may be smaller. } sb.Append(_charBuffer, 0, charsRead); currPos += n; } while (currPos < stringLength); return(StringBuilderCache.GetStringAndRelease(sb)); }