public CharBit(string characters, int bitSize)
{
Characters = characters;
BitSize = bitSize;
}
} // Define the character BaseBits and their corresponding bit sizes
public class CharBits //encode/decode keys
{ // Structure to store base information string of encrypt characters and relevant bitsize
//internal static string Bin_In=""; //References for debugging and checking BIN IN and BIN OUT; commented out below.
// static string Bin_Out=""; //References for debugging and checking BIN IN and BIN OUT; commented out below.
public static readonly CharBit[] Key = //DEFINE CONSTANT ARRAYS FOR INPUT/OUTPUT BSAED ON LETTERS
{
//GUID is a 128 bit integer--------------------------------------------------------------------------------------
// 'do not change strings - will match through bit compresion and will change the whole field base encoding!
// '5 Bit - Simplified - ignoring upper and lower case
// '5 bit - would allow for names (128bitGUID/5bit=)25 characters long - 2^5(32) character positions available
// 'REQUIRES UCASE convert prior to checking. can contain a few digits only
// 'Optional simpler base 5bit- not used - do not change this - it will change the whole field base and compression!
// ''''''''''0'''''''''1'''''''''2'''''''''3'*< length of 32 chars MAX (32 positions available)
// ''''''''''01234567890123456789012345678901 ''NoSpaces! IGNORE case for encode/decode
new CharBit(".ABCDEFGHIJKLMNOPQRSTUVWXYZ_1234", 5),
// <6-bit is default>''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// '6 bit - allows for names (128bitGUID/6bit=)21 characters long - 2^6(64) character positons available CASE matters in revit parameters foo is different from FOO
// 'do not change this - it will change the whole field base and compression!
// ''''''''''0'''''''''1'''''''''2'''''''''3'''''''''4'''''''''5'''''''''6''''
// ''''''''''0123456789012345678901234567890123456789012345678901234567890123 ''NoSpaces!
new CharBit(".ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789abcdefghijklmnopqrstuvwxyz", 6),
// 'Encoding bitsize
// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// '7 bit - allow for names (128bitGUID/7bit=)18 characters long
// 'do not change this - it will change the whole field base and compression!
// ''''''''''0'''''''''1'''''''''2'''''''''3'''''''''4'''''''''5'''''''''6'''''''''7'''''''''''12 *<127
// ''''''''''01234567890123456789012345678901234567890123456789012345678901234567890123456789---01234567
new CharBit(".ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789abcdefghijklmnopqrstuvwxyz !\"#$%&'()*+", 7),
// 'Encoding bitsize
// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// '8 bit - allows for (128bitGUID/8bit=)16 characters but uses all 255 characters and symbvols available.
// 'Same as straight hex encoding xFF 256 bits - mostly 173 wasted spaces
// ''''''''''0'''''''''1'''''''''2'''''''''3'''''''''4'''''''''5'''''''''6'''''''''7'''''''''8'''
// ''''''''''012345678901234567890123456789012345678901234567890123456789012345678901234567890123
new CharBit(".ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789abcdefghijklmnopqrstuvwxyz !\"#$%&'()*+:;=@^`", 8)
};
}
public class GUID_Encode //Entry point to encode GUIDs <<<<<<<<START<<<<<<<<<<<<<<<<
{
public static bool GUIDMatches(Guid gGUID, string strVarName, int BitLimit = 5) //Checks if GUID Matches varname in BitLimit
{
bool Matches = (gGUID == StringToGUID(strVarName, BitLimit));
return (Matches);
}
public static System.Guid StringToGUID(string strVarName, int BitLimit = 5) //Default bit limit is 5
{
if (BitLimit > 8)
{
BitLimit = 8; //not more than 8 bits
}
if (BitLimit < 5)
{
BitLimit = 5; //not less than 5 bits
}
if (BitLimit == 5) //To Uppercase for 5 bit limited character set
{
strVarName = strVarName.ToUpper();
} //5-bit all caps
int NumChar = 128 / BitLimit; //Calculate max length of names with bit packing
strVarName = strVarName.PadRight(NumChar, '.'); //Pad with .
strVarName = strVarName.Substring(0, NumChar); //chop off excessive characters in name to meet characters VS bitsize requirements
return String_To_GUID(strVarName, BitLimit); //new Guid(strGUID);
}
//private static string String_to_6Bit2HexGUID(string varName)
private static System.Guid String_To_GUID(string varName, int BitLimit = 5)
{
CharBit cb = CharBits.Key[BitLimit - 5]; //for bit limit 5-8
string strGUID = string.Empty;
string strBin = string.Empty;
string strBit = string.Empty;
//long LongBit;
if (BitLimit == 5) //Redundant ToUpper for 5 bit a precaution
{
varName = varName.ToUpper();
}
for (int i = 0; i < varName.Length; i++)
{
char c = varName.Substring(i, 1)[0]; //single character
int cpos = cb.Characters.IndexOf(c); //index position of character to max char in set //-1 if not found
if (cpos == -1)
{
cpos = cb.Characters.IndexOf('.'); //reset to '.' character as a replacement for not found.
}
strBit = Dec2Bin(cpos, BitLimit); //from charbits return position of character
strBin = strBit + strBin; //Most dignificant bits at left so prepend values
}
//CharBits.Bin_In = strBin;
strBin = strBin.PadLeft(128, '0'); //pad out additional MSBs with 0's in odd-bit sizes
//CharBits.Bin_In = strBin;
return Str128BinaryToGuid(strBin);
}
private static string Dec2Bin(long longIn, int BitLimit = 5) //convert to BitLimit-bit to pack bits. This is the bit chunk for the out later.
{
string dec2Bin = "";
longIn = (long)Math.Floor(Convert.ToDecimal(longIn));
while (longIn != 0)
{
dec2Bin = $"{longIn - 2 * (long)(longIn / 2)}{dec2Bin}";
longIn = (long)(longIn / 2);
}
if (dec2Bin.Length > BitLimit)
{
dec2Bin = "Error - Number exceeds specified bit size";
}
dec2Bin = $"{dec2Bin.PadLeft(BitLimit, '0')}"; //string is pack with the number of bits in bit limit MSB-Left
return dec2Bin;
}
private static Guid Str128BinaryToGuid(string binaryString)
{//Output was failing to match in 1st half od BIN str from GUID
//The issue lies in the byte order of the Guid structure. The Guid structure stores the bytes in
//little-endian format, which means the byte order needs to be reversed when converting to and from binary.
binaryString = binaryString.PadLeft(128, '0');
ulong high = Convert.ToUInt64(binaryString.Substring(0, 64), 2);
ulong low = Convert.ToUInt64(binaryString.Substring(64), 2);
byte[] bytes = new byte[16];
BitConverter.GetBytes(high).CopyTo(bytes, 0);
BitConverter.GetBytes(low).CopyTo(bytes, 8);
Array.Reverse(bytes); // Reverse the byte order to match little-endian format
Guid gGUID = new Guid(bytes);
return gGUID;
}
public static string GUIDtoString(Guid gGUID, int BitLimit = 5) //Default bit limit is 5
{
if (BitLimit > 8) BitLimit = 8; //not more than 8 bits
if (BitLimit < 5) BitLimit = 5; //not less than 5 bits
///return new Guid(strGUID);
return GUID_To_String(gGUID, BitLimit);
}
private static string GUID_To_String(Guid gGUID, int BitLimit = 5)
{
CharBit cb = CharBits.Key[BitLimit - 5]; //for bit limit 5-8
string strBin = string.Empty;
string strByte;
string strVarName = string.Empty;
int pos;
strBin = GuidToStr128Bin(gGUID); //convert to binary. Matches finally! The Guid structure stores the bytes in
//CharBits.Bin_Out = strBin;
string ss = strBin;
while (ss.Length >= BitLimit) // Stop when remaining string length is less than BitLimit
{
strByte = ss.Substring(ss.Length - BitLimit);
ss = ss.Substring(0, ss.Length - strByte.Length);
pos = Convert.ToInt32(strByte, 2);
strVarName += cb.Characters[pos];
}
return strVarName;
}
private static string GuidToStr128Bin(Guid gGUID)
{
byte[] bytes = gGUID.ToByteArray();
Array.Reverse(bytes); // Reverse the byte order to match little-endian format
ulong high = BitConverter.ToUInt64(bytes, 0);
ulong low = BitConverter.ToUInt64(bytes, 8);
string binaryString = Convert.ToString((long)high, 2).PadLeft(64, '0') + Convert.ToString((long)low, 2).PadLeft(64, '0');
return binaryString;
}
}