Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Security;
using System.Management.Automation;
using System.Collections.Generic;
using System.Management.Automation.Internal;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
// Once Serialization is available on CoreCLR: using System.Runtime.Serialization.Formatters.Binary;

namespace Microsoft.PowerShell.Commands
Expand Down Expand Up @@ -236,69 +237,17 @@ private void ProcessFileContent(string path)
private void ProcessObjectContent(PSObject inputObject)
{
object obj = inputObject.BaseObject;
byte[] inputBytes = null;

switch (obj)
if (obj is System.IO.FileSystemInfo fsi)
{
case System.IO.FileSystemInfo fsi:
string[] path = { fsi.FullName };
List<string> pathsToProcess = ResolvePaths(path, true);
ProcessPath(pathsToProcess);
return;
case string str:
inputBytes = Encoding.GetBytes(str);
break;
case byte b:
inputBytes = new byte[] { b };
break;
case byte[] byteArray:
inputBytes = byteArray;
break;
case Int32 iInt32:
inputBytes = BitConverter.GetBytes(iInt32);
break;
case Int32[] i32s:
int i32 = 0;
inputBytes = new byte[sizeof(Int32) * i32s.Length];
Span<byte> inputStreamArray32 = inputBytes;

foreach (Int32 value in i32s)
{
BitConverter.TryWriteBytes(inputStreamArray32.Slice(i32), value);
i32 += sizeof(Int32);
}

break;
case Int64 iInt64:
inputBytes = BitConverter.GetBytes(iInt64);
break;
case Int64[] inputInt64s:
int i64 = 0;
inputBytes = new byte[sizeof(Int64) * inputInt64s.Length];
Span<byte> inputStreamArray64 = inputBytes;

foreach (Int64 value in inputInt64s)
{
BitConverter.TryWriteBytes(inputStreamArray64.Slice(i64), value);
i64 += sizeof(Int64);
}

break;

// If the object type is not supported, throw an error. Once Serialization is
// available on CoreCLR, other types will be supported.
default:
{
string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexTypeNotSupported, obj.GetType());
ErrorRecord errorRecord = new ErrorRecord(new ArgumentException(errorMessage),
"FormatHexTypeNotSupported",
ErrorCategory.InvalidArgument,
obj.GetType());
WriteError(errorRecord);
break;
}
}

byte[] inputBytes = ConvertToByteArray(obj);

if (inputBytes != null)
{
int offset = Math.Min(inputBytes.Length, Offset < (long)int.MaxValue ? (int)Offset : int.MaxValue);
Expand All @@ -312,6 +261,94 @@ private void ProcessObjectContent(PSObject inputObject)
WriteHexidecimal(inputBytes, null, 0);
}
}
else
{
string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexTypeNotSupported, obj.GetType());
ErrorRecord errorRecord = new ErrorRecord(new ArgumentException(errorMessage),
"FormatHexTypeNotSupported",
ErrorCategory.InvalidArgument,
obj.GetType());
WriteError(errorRecord);
}
}

private byte[] ConvertToByteArray(object inputObject)
{
if (inputObject is string str)
{
return Encoding.GetBytes(str);
}

var baseType = inputObject.GetType();
byte[] result = null;
int elements = 1;
bool isArray = false;
bool isBool = false;
bool isEnum = false;
if (baseType.IsArray)
{
baseType = baseType.GetElementType();
dynamic dynamicObject = inputObject;
elements = (int)dynamicObject.Length;
isArray = true;
}

if (baseType.IsEnum)
{
baseType = baseType.GetEnumUnderlyingType();
isEnum = true;
}

if (baseType.IsPrimitive && elements > 0)
{
if (baseType == typeof(bool))
{
isBool = true;
}

var elementSize = Marshal.SizeOf(baseType);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong, but wasn't one of @lzybkr's comments that this would return the wrong size for boolean values?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is ok - only local bool var-s have 4 byte size, rest - 1 byte.

result = new byte[elementSize * elements];
if (!isArray)
{
inputObject = new object[] { inputObject };
}

int index = 0;
foreach (dynamic obj in (Array)inputObject)
{
if (elementSize == 1)
{
result[index] = (byte)obj;
}
else
{
dynamic toBytes;
if (isEnum)
{
toBytes = Convert.ChangeType(obj, baseType);
}
else if (isBool)
{
// bool is 1 byte apparently
toBytes = Convert.ToByte(obj);
}
else
{
toBytes = obj;
}

var bytes = BitConverter.GetBytes(toBytes);
for (int i = 0; i < bytes.Length; i++)
{
result[i + index] = bytes[i];
}
}

index += elementSize;
}
}

return result;
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,42 @@ Describe "FormatHex" -tags "CI" {
Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
}
@{
Name = "Can process enum type 'fhx -InputObject ([DisplayHintType]::DateTime)'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType]::DateTime
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
}
@{
Name = "Can process DisplayHintType[] type 'fhx -InputObject ([DisplayHintType[]](DateTime, Time))'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime)
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
}
@{
Name = "Can process DisplayHintType[] type 'fhx -InputObject ([DisplayHintType[]](DateTime, Time))'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime, [Microsoft.PowerShell.Commands.DisplayHintType]::Time)
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 01 00 00 00 ........"
}
@{
Name = "Can process char type 'fhx -InputObject ([char]`'A`')'"
InputObject = [char]'A'
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type 'fhx -InputObject ([char[]](`'A`'))'"
InputObject = [char[]]('A')
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type 'fhx -InputObject ([char[]](`'A`', 'B'))'"
InputObject = [char[]]('A', 'B')
Count = 1
ExpectedResult = "00000000000000000000 41 42 AB"
}
)

It "<Name>" -TestCase $testCases{
Expand Down Expand Up @@ -173,6 +209,44 @@ Describe "FormatHex" -tags "CI" {
Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
}
@{
Name = "Can process enum type '[DisplayHintType]::DateTime | fhx"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType]::DateTime
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
}
@{
Name = "Can process DisplayHintType[] type '[DisplayHintType[]](DateTime) | fhx'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime)
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
}
@{
Name = "Can process DisplayHintType[] type '[DisplayHintType[]](DateTime, Time) | fhx'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime, [Microsoft.PowerShell.Commands.DisplayHintType]::Time)
Count = 2
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
ExpectedSecondResult = "00000000000000000000 01 00 00 00 ...."
}
@{
Name = "Can process char type '[char]`'A`' | fhx'"
InputObject = [char]'A'
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type '[char[]](`'A`') | fhx'"
InputObject = [char[]]('A')
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type '[char[]](`'A`', 'B') | fhx'"
InputObject = [char[]]('A', 'B')
Count = 2
ExpectedResult = "00000000000000000000 41 A"
ExpectedSecondResult = "00000000000000000000 42 B"
}
)

It "<Name>" -Testcase $testCases {
Expand Down