382 lines
13 KiB
C#
382 lines
13 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Management.Automation;
|
|
using System.Text;
|
|
|
|
[module: SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope = "type", Target = "~T:Microsoft.PowerShell.Commands.ByteCollection")]
|
|
|
|
namespace Microsoft.PowerShell.Commands
|
|
{
|
|
/// <summary>
|
|
/// Don't use! The API is obsolete!.
|
|
/// </summary>
|
|
[Obsolete("This class is included in this SDK for completeness only. The members of this class cannot be used directly, nor should this class be used to derive other classes.", true)]
|
|
public enum TextEncodingType
|
|
{
|
|
/// <summary>
|
|
/// No encoding.
|
|
/// </summary>
|
|
Unknown,
|
|
|
|
/// <summary>
|
|
/// Unicode encoding.
|
|
/// </summary>
|
|
String,
|
|
|
|
/// <summary>
|
|
/// Unicode encoding.
|
|
/// </summary>
|
|
Unicode,
|
|
|
|
/// <summary>
|
|
/// Byte encoding.
|
|
/// </summary>
|
|
Byte,
|
|
|
|
/// <summary>
|
|
/// Big Endian Unicode encoding.
|
|
/// </summary>
|
|
BigEndianUnicode,
|
|
|
|
/// <summary>
|
|
/// Big Endian UTF32 encoding.
|
|
/// </summary>
|
|
BigEndianUTF32,
|
|
|
|
/// <summary>
|
|
/// UTF8 encoding.
|
|
/// </summary>
|
|
Utf8,
|
|
|
|
/// <summary>
|
|
/// UTF7 encoding.
|
|
/// </summary>
|
|
Utf7,
|
|
|
|
/// <summary>
|
|
/// ASCII encoding.
|
|
/// </summary>
|
|
Ascii,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Utility class to contain resources for the Microsoft.PowerShell.Utility module.
|
|
/// </summary>
|
|
[Obsolete("This class is obsolete", true)]
|
|
public static class UtilityResources
|
|
{
|
|
/// <summary>
|
|
/// </summary>
|
|
public static string PathDoesNotExist { get { return UtilityCommonStrings.PathDoesNotExist; } }
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
public static string FileReadError { get { return UtilityCommonStrings.FileReadError; } }
|
|
|
|
/// <summary>
|
|
/// The resource string used to indicate 'PATH:' in the formating header.
|
|
/// </summary>
|
|
public static string FormatHexPathPrefix { get { return UtilityCommonStrings.FormatHexPathPrefix; } }
|
|
|
|
/// <summary>
|
|
/// Error message to indicate that requested algorithm is not supported on the target platform.
|
|
/// </summary>
|
|
public static string AlgorithmTypeNotSupported { get { return UtilityCommonStrings.AlgorithmTypeNotSupported; } }
|
|
|
|
/// <summary>
|
|
/// The file '{0}' could not be parsed as a PowerShell Data File.
|
|
/// </summary>
|
|
public static string CouldNotParseAsPowerShellDataFile { get { return UtilityCommonStrings.CouldNotParseAsPowerShellDataFile; } }
|
|
}
|
|
|
|
/// <summary>
|
|
/// ByteCollection is used as a wrapper class for the collection of bytes.
|
|
/// </summary>
|
|
public class ByteCollection
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
|
|
/// </summary>
|
|
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
|
|
/// <param name="value">Underlying bytes stored in the collection.</param>
|
|
/// <param name="path">Indicates the path of the file whose contents are wrapped in the ByteCollection.</param>
|
|
[Obsolete("The constructor is deprecated.", true)]
|
|
public ByteCollection(uint offset, byte[] value, string path)
|
|
: this((ulong)offset, value, path)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
|
|
/// </summary>
|
|
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
|
|
/// <param name="value">Underlying bytes stored in the collection.</param>
|
|
/// <param name="path">Indicates the path of the file whose contents are wrapped in the ByteCollection.</param>
|
|
public ByteCollection(ulong offset, byte[] value, string path)
|
|
{
|
|
if (value == null)
|
|
{
|
|
throw PSTraceSource.NewArgumentNullException(nameof(value));
|
|
}
|
|
|
|
Offset64 = offset;
|
|
Bytes = value;
|
|
Path = path;
|
|
Label = path;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
|
|
/// </summary>
|
|
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
|
|
/// <param name="value">Underlying bytes stored in the collection.</param>
|
|
[Obsolete("The constructor is deprecated.", true)]
|
|
public ByteCollection(uint offset, byte[] value)
|
|
: this((ulong)offset, value)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
|
|
/// </summary>
|
|
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
|
|
/// <param name="value">Underlying bytes stored in the collection.</param>
|
|
public ByteCollection(ulong offset, byte[] value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
throw PSTraceSource.NewArgumentNullException(nameof(value));
|
|
}
|
|
|
|
Offset64 = offset;
|
|
Bytes = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
|
|
/// </summary>
|
|
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
|
|
/// <param name="label">
|
|
/// The label for the byte group. This may be a file path or a formatted identifying string for the group.
|
|
/// </param>
|
|
/// <param name="value">Underlying bytes stored in the collection.</param>
|
|
public ByteCollection(ulong offset, string label, byte[] value)
|
|
: this(offset, value)
|
|
{
|
|
Label = label;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
|
|
/// </summary>
|
|
/// <param name="value">Underlying bytes stored in the collection.</param>
|
|
public ByteCollection(byte[] value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
throw PSTraceSource.NewArgumentNullException(nameof(value));
|
|
}
|
|
|
|
Bytes = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the Offset address to be used while displaying the bytes in the collection.
|
|
/// </summary>
|
|
[Obsolete("The property is deprecated, please use Offset64 instead.", true)]
|
|
public uint Offset
|
|
{
|
|
get
|
|
{
|
|
return (uint)Offset64;
|
|
}
|
|
|
|
private set
|
|
{
|
|
Offset64 = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the Offset address to be used while displaying the bytes in the collection.
|
|
/// </summary>
|
|
public ulong Offset64 { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Gets underlying bytes stored in the collection.
|
|
/// </summary>
|
|
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
|
public byte[] Bytes { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the path of the file whose contents are wrapped in the ByteCollection.
|
|
/// </summary>
|
|
public string Path { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the hexadecimal representation of the <see cref="Offset64"/> value.
|
|
/// </summary>
|
|
public string HexOffset { get => string.Format(CultureInfo.CurrentCulture, "{0:X16}", Offset64); }
|
|
|
|
/// <summary>
|
|
/// Gets the type of the input objects used to create the <see cref="ByteCollection"/>.
|
|
/// </summary>
|
|
public string Label { get; }
|
|
|
|
private const int BytesPerLine = 16;
|
|
|
|
private string _hexBytes = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets a space-delimited string of the <see cref="Bytes"/> in this <see cref="ByteCollection"/>
|
|
/// in hexadecimal format.
|
|
/// </summary>
|
|
public string HexBytes
|
|
{
|
|
get
|
|
{
|
|
if (_hexBytes == string.Empty)
|
|
{
|
|
StringBuilder line = new(BytesPerLine * 3);
|
|
|
|
foreach (var currentByte in Bytes)
|
|
{
|
|
line.AppendFormat(CultureInfo.CurrentCulture, "{0:X2} ", currentByte);
|
|
}
|
|
|
|
_hexBytes = line.ToString().Trim();
|
|
}
|
|
|
|
return _hexBytes;
|
|
}
|
|
}
|
|
|
|
private string _ascii = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets the ASCII string representation of the <see cref="Bytes"/> in this <see cref="ByteCollection"/>.
|
|
/// </summary>
|
|
/// <value></value>
|
|
public string Ascii
|
|
{
|
|
get
|
|
{
|
|
if (_ascii == string.Empty)
|
|
{
|
|
StringBuilder ascii = new(BytesPerLine);
|
|
|
|
foreach (var currentByte in Bytes)
|
|
{
|
|
var currentChar = (char)currentByte;
|
|
if (currentChar == 0x0)
|
|
{
|
|
ascii.Append(' ');
|
|
}
|
|
else if (char.IsControl(currentChar))
|
|
{
|
|
ascii.Append((char)0xFFFD);
|
|
}
|
|
else
|
|
{
|
|
ascii.Append(currentChar);
|
|
}
|
|
}
|
|
|
|
_ascii = ascii.ToString();
|
|
}
|
|
|
|
return _ascii;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Displays the hexadecimal format of the bytes stored in the collection.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString()
|
|
{
|
|
const int BytesPerLine = 16;
|
|
const string LineFormat = "{0:X16} ";
|
|
|
|
// '16 + 3' comes from format "{0:X16} ".
|
|
// '16' comes from '[Uint64]::MaxValue.ToString("X").Length'.
|
|
StringBuilder nextLine = new(16 + 3 + (BytesPerLine * 3));
|
|
StringBuilder asciiEnd = new(BytesPerLine);
|
|
|
|
// '+1' comes from 'result.Append(nextLine.ToString() + " " + asciiEnd.ToString());' below.
|
|
StringBuilder result = new(nextLine.Capacity + asciiEnd.Capacity + 1);
|
|
|
|
if (Bytes.Length > 0)
|
|
{
|
|
long charCounter = 0;
|
|
|
|
var currentOffset = Offset64;
|
|
|
|
nextLine.AppendFormat(CultureInfo.InvariantCulture, LineFormat, currentOffset);
|
|
|
|
foreach (byte currentByte in Bytes)
|
|
{
|
|
// Display each byte, in 2-digit hexadecimal, and add that to the left-hand side.
|
|
nextLine.AppendFormat("{0:X2} ", currentByte);
|
|
|
|
// If the character is printable, add its ascii representation to
|
|
// the right-hand side. Otherwise, add a dot to the right hand side.
|
|
var currentChar = (char)currentByte;
|
|
if (currentChar == 0x0)
|
|
{
|
|
asciiEnd.Append(' ');
|
|
}
|
|
else if (char.IsControl(currentChar))
|
|
{
|
|
asciiEnd.Append((char)0xFFFD);
|
|
}
|
|
else
|
|
{
|
|
asciiEnd.Append(currentChar);
|
|
}
|
|
|
|
charCounter++;
|
|
|
|
// If we've hit the end of a line, combine the right half with the
|
|
// left half, and start a new line.
|
|
if ((charCounter % BytesPerLine) == 0)
|
|
{
|
|
result.Append(nextLine).Append(' ').Append(asciiEnd);
|
|
nextLine.Clear();
|
|
asciiEnd.Clear();
|
|
currentOffset += BytesPerLine;
|
|
nextLine.AppendFormat(CultureInfo.InvariantCulture, LineFormat, currentOffset);
|
|
|
|
// Adding a newline to support long inputs strings flowing through InputObject parameterset.
|
|
if ((charCounter <= Bytes.Length) && string.IsNullOrEmpty(Path))
|
|
{
|
|
result.AppendLine();
|
|
}
|
|
}
|
|
}
|
|
|
|
// At the end of the file, we might not have had the chance to output
|
|
// the end of the line yet. Only do this if we didn't exit on the 16-byte
|
|
// boundary, though.
|
|
if ((charCounter % 16) != 0)
|
|
{
|
|
while ((charCounter % 16) != 0)
|
|
{
|
|
nextLine.Append(' ', 3);
|
|
asciiEnd.Append(' ');
|
|
charCounter++;
|
|
}
|
|
|
|
result.Append(nextLine).Append(' ').Append(asciiEnd);
|
|
}
|
|
}
|
|
|
|
return result.ToString();
|
|
}
|
|
}
|
|
}
|