using System;
using System.Collections.Generic;
//
public class Program
{
public static bool IsHex(IEnumerable<char> chars)
{
bool isHex;
foreach(var c in chars)
{
isHex = ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F'));
if(!isHex)
return false;
}
return true;
}
public static void Main()
{
//Source - http://www.hanselman.com/blog/BATCHFILEVOODOODetermineIfMultipleAndWhichVersionsOfAnMSIinstalledProductAreInstalledUsingUpgradeCode.aspx
//like to but to bulky - https://docs.microsoft.com/en-us/dotnet/standard/base-types/how-to-define-and-use-custom-numeric-format-providers
//https://installpac.wordpress.com/2008/03/31/packed-guids-darwin-descriptors-and-windows-installer-reference-counting/
//PROTO
//{12345678-ABCD-WXYZ-1234-ABCDEFGHIJKL}
//should be-> 87654321DCBAZYXW2134BADCFEHGJILK
//string inStrGUID = "{12345678-ABCD-WXYZ-1234-ABCDEFGHIJKL}"; //cannot use this contrived GUID has hex values above > (A-F)
string inStrGUID = "{12345678-ABCD-EFAB-1234-ABCDEFABCDEF}";
string expectedCompressedGUID = "87654321DCBABAFE2143BADCFEBADCFE";
//https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse?view=netframework-4.7.2 - N has no dashes
string outputFormat = "N"; //outputFormat can be N, D, B, P - N has no dashes
string outCompressedGuid = "";
string outDecompressedGuid = "";
Guid inGuid = new Guid();
Guid outGuid = new Guid();
Guid outDCGuid = new Guid();
bool isValidGuid = Guid.TryParse(inStrGUID, out inGuid);
Console.WriteLine("Input GUID " + inStrGUID+ " is valid? "+isValidGuid);
if (isValidGuid) {
string raw = inGuid.ToString("N"); //N for no dashes
char[] aRaw = raw.ToCharArray();
//compressed format reverses 11 byte sequences of the original guid
int[] revs
= new int[]{8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2};
int pos = 0;
for (int i = 0; i < revs.Length; i++)
{
Array.Reverse(aRaw, pos, revs[i]);
pos += revs[i];
}
string newstrGuid = new string(aRaw);
bool isoutValidGuid = Guid.TryParse(newstrGuid, out outGuid);
if ( isoutValidGuid ) {
//GUID in registry are all caps.
outCompressedGuid = outGuid.ToString(outputFormat).ToUpper();
Console.WriteLine("out CGUID "+ outGuid.ToString("B").ToUpper()+" before full compression (removal of dashes) here for readability"); //for readability
Console.WriteLine("\nCompressed guid is "+ outCompressedGuid );
if (outCompressedGuid == expectedCompressedGUID)
Console.WriteLine("Matched expectations.");
else
Console.WriteLine("Did not met expectations.");
} else
Console.WriteLine("Failed to compress GUID.");
}
Console.WriteLine("\nInput Compressed GUID " + outCompressedGuid);
char[] chrArrCGUID = outCompressedGuid.ToCharArray();
//Here's a typical GUID Compressed in a Registry Key
//what if ? S-1-5-21-xxxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxx - split on new char[] {' ','-'} check any that are length 32
//Expand/Decompress/Decrypt Compressed GUID
if (outCompressedGuid.Length == 32 && Program.IsHex(chrArrCGUID)==true){ //validate potential Compressed GUID
int[] reversalidxs= new int[]{8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2};
int pos = 0;
for (int i = 0; i < reversalidxs.Length; i++)
{
Array.Reverse(chrArrCGUID, pos, reversalidxs[i]);
pos += reversalidxs[i];
}
string newstrGuid = new string(chrArrCGUID);
bool isoutValidDCGuid = Guid.TryParse(newstrGuid, out outDCGuid );
if ( isoutValidDCGuid ) {
//GUID in registry are all caps.
outDecompressedGuid = outDCGuid.ToString("B").ToUpper();
//Console.WriteLine("\nInput Compressed GUID "+ outDCGuid.ToString("B").ToUpper()+" this line for comparison only"); //for readability
Console.WriteLine("Output Decomprsd GUID "+ outDCGuid.ToString("N").ToUpper()+" this line for comparison only"); //for readability
Console.WriteLine("\nDecompressed compressed guid is "+ outDecompressedGuid );
}
}
else
Console.WriteLine("Failed to decompressed CGUID.");
}
}