/// <summary> /// Proto encoding of Dictionary [uint, byte[]]. /// Use when key is less then 4 bytes (less then 268mln). /// Value byte[0] will be presented as null after decoding /// </summary> /// <param name="d"></param> /// <param name="compression">compression method extra applied to the outgoing byte array</param> /// <returns></returns> public static byte[] Encode_DICT_PROTO_UINT_BYTEARRAY(this IDictionary<uint, byte[]> d, Compression.eCompressionMethod compression = Compression.eCompressionMethod.NoCompression) { if (d == null || d.Count == 0) return null; List<byte[]> ar = new List<byte[]>(); ulong size = 0; byte[] tar = null; foreach (var el in d) { //Setting key tar = GetVarintBytes(el.Key); size += (ulong)tar.Length; ar.Add(tar); //Setting length of value tar = el.Value == null ? new byte[] { 0 } : GetVarintBytes((uint)el.Value.Length); //Supporting 0 length, will be null then size += (ulong)tar.Length; ar.Add(tar); //Setting value size += (ulong)(el.Value == null ? 0 : el.Value.Length); if (el.Value != null && el.Value.Length > 0) ar.Add(el.Value); } byte[] encB = new byte[size]; int pt = 0; foreach (var el in ar) { Buffer.BlockCopy(el, 0, encB, pt, el.Length); pt += el.Length; } switch (compression) { case Compression.eCompressionMethod.Gzip: encB = encB.GZip_Compress(); break; } return encB; }
/// <summary> /// Used when parameter is encoded with Encode_DICT_PROTO_UINT_BYTEARRAY. /// Returns Dictionary [uint, byte[]] /// </summary> /// <param name="encB"></param> /// <param name="retD">Instantiated Dictionary must be supplied and will be returned filled</param> /// <param name="compression">compression method supplied by Encode_DICT_PROTO_UINT_BYTEARRAY</param> public static void Decode_DICT_PROTO_UINT_BYTEARRAY(this byte[] encB, IDictionary<uint, byte[]> retD, Compression.eCompressionMethod compression = Compression.eCompressionMethod.NoCompression) { if (encB == null || encB.Length < 1) return; switch (compression) { case Compression.eCompressionMethod.Gzip: encB = encB.GZip_Decompress(); break; } byte mode = 0; byte[] sizer = new byte[4]; int size = 0; uint key = 0; uint valLen = 0; byte[] val = null; int valCnt = 0; Action ClearSizer = () => { sizer[0] = 0; sizer[1] = 0; sizer[2] = 0; sizer[3] = 0; size = 0; }; //0 - reading key //1 - reading size of value //2 - reading value foreach (byte el in encB) { switch (mode) { case 0: //Key, Size of BT // if ((el & 0x80) > 0) { sizer[size] = el; size++; } else { mode = 1; sizer[size] = el; size++; key = ToUInt32(sizer); ClearSizer(); } break; case 1: //Value Size if ((el & 0x80) > 0) { sizer[size] = el; size++; } else { mode = 2; sizer[size] = el; size++; valLen = ToUInt32(sizer); ClearSizer(); if (valLen == 0) { retD.Add(key, null); mode = 0; break; } val = new byte[valLen]; valCnt = 0; } break; case 2: val[valCnt] = el; valCnt++; if (valCnt == valLen) { retD.Add(key, val); mode = 0; break; } break; } } return; }
/// <summary> /// Proto encoding of Dictionary [string, HashSet[uint]]. /// Hashset can be null, after decoding istantiated, zero-length hashset will be returned in this case. /// </summary> /// <param name="d"></param> /// <param name="compression"></param> /// <returns></returns> public static byte[] Encode_DICT_PROTO_STRING_UINTHASHSET(this IDictionary<string, HashSet<uint>> d, Compression.eCompressionMethod compression = Compression.eCompressionMethod.NoCompression) { if (d == null || d.Count == 0) return null; List<byte[]> ar = new List<byte[]>(); int size = 0; byte[] tar = null; byte[] tar1 = null; foreach (var el in d) { //Setting key tar = el.Key.To_UTF8Bytes(); tar1 = GetVarintBytes((uint)tar.Length); ar.Add(tar1);//length of key ar.Add(tar);//key self size += tar1.Length; size += tar.Length; //Setting count of hashset tar = GetVarintBytes((uint)(el.Value == null ? 0 : el.Value.Count)); ar.Add(tar); size += tar.Length; //Hashset if (el.Value != null) { foreach (var evl in el.Value) { tar = GetVarintBytes(evl); ar.Add(tar); size += tar.Length; } } } byte[] encB = new byte[size]; int pt = 0; foreach (var el in ar) { Buffer.BlockCopy(el, 0, encB, pt, el.Length); pt += el.Length; } switch (compression) { case Compression.eCompressionMethod.Gzip: encB = encB.GZip_Compress(); break; } return encB; }
/// <summary> /// Decodes byte[] into Dictionary [string, HashSet[uint]] /// </summary> /// <param name="encB"></param> /// <param name="retD"></param> /// <param name="compression"></param> /// <returns></returns> public static void Decode_DICT_PROTO_STRING_UINTHASHSET(this byte[] encB, IDictionary<string, HashSet<uint>> retD, Compression.eCompressionMethod compression = Compression.eCompressionMethod.NoCompression) { if (encB == null || encB.Length < 1) return; switch (compression) { case Compression.eCompressionMethod.Gzip: encB = encB.GZip_Decompress(); break; } byte mode = 0; byte[] sizer = new byte[4]; int size = 0; uint keyLength = 0; string key = ""; uint valCnt = 0; Action ClearSizer = () => { sizer[0] = 0; sizer[1] = 0; sizer[2] = 0; sizer[3] = 0; size = 0; }; //0 - reading key //1 - HashSet Count //2 - reading Hashset elements one by one byte el = 0; int i = 0; int hc = 0; //Hashset grabbed count HashSet<uint> mhs = null; while (i < encB.Length) { el = encB[i]; switch (mode) { case 0: if ((el & 0x80) > 0) { sizer[size] = el; size++; } else { hc = 0; mode = 1; sizer[size] = el; size++; keyLength = ToUInt32(sizer); key = System.Text.Encoding.UTF8.GetString(encB.Substring(i + 1, (int)keyLength)); i += (int)keyLength + 1; ClearSizer(); continue; } break; case 1: //HashSet Count if ((el & 0x80) > 0) { sizer[size] = el; size++; } else { mode = 2; sizer[size] = el; size++; valCnt = ToUInt32(sizer); ClearSizer(); if (valCnt == 0) { retD.Add(key, new HashSet<uint>()); mode = 0; } } break; case 2: if ((el & 0x80) > 0) { sizer[size] = el; size++; } else { sizer[size] = el; size++; if (hc == 0) mhs = new HashSet<uint>(); mhs.Add(ToUInt32(sizer)); hc++; ClearSizer(); if (valCnt == hc) { mode = 0; retD.Add(key, mhs); } } break; } i++; } return; }