using KFDtool.P25.TransferConstructs; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KFDtool.P25.Partition { public class KeyPartitioner { private static void CheckForDifferentKeyLengths(List inKeys) { Dictionary len = new Dictionary(); foreach (CmdKeyItem key in inKeys) { if (!len.ContainsKey(key.AlgorithmId)) { len.Add(key.AlgorithmId, key.Key.Count); } else { if (len[key.AlgorithmId] != key.Key.Count) { throw new Exception("more than one length of key per algorithm id"); } } } } private static int CalcMaxKeysPerKmm(int keyLength) { // TODO make this calc more dynamic int maxBytes = 512; int availBytes = maxBytes - 27; int keyItemBytes = 5 + keyLength; int maxKeys = availBytes / keyItemBytes; if (maxKeys < 1) { throw new Exception("key too large for kmm"); } return maxKeys; } private static void PartitionByAlg(List inKeys, List> outKeys) { Dictionary> alg = new Dictionary>(); foreach (CmdKeyItem keyItem in inKeys) { if (!alg.ContainsKey(keyItem.AlgorithmId)) { alg.Add(keyItem.AlgorithmId, new List()); } alg[keyItem.AlgorithmId].Add(keyItem); } foreach (KeyValuePair> algGroup in alg) { int maxKeys = CalcMaxKeysPerKmm(algGroup.Value[0].Key.Count); PartitionByType(maxKeys, algGroup.Value, outKeys); } } private static void PartitionByType(int maxKeys, List inKeys, List> outKeys) { List tek = new List(); List kek = new List(); foreach (CmdKeyItem keyItem in inKeys) { if (keyItem.IsKek) { kek.Add(keyItem); } else { tek.Add(keyItem); } } PartitionByActive(maxKeys, tek, outKeys); PartitionByActive(maxKeys, kek, outKeys); } private static void PartitionByActive(int maxKeys, List inKeys, List> outKeys) { List act = new List(); List def = new List(); foreach (CmdKeyItem keyItem in inKeys) { if (keyItem.UseActiveKeyset) { act.Add(keyItem); } else { def.Add(keyItem); } } PartitionByLength(maxKeys, act, outKeys); PartitionByKeyset(maxKeys, def, outKeys); } private static void PartitionByKeyset(int maxKeys, List inKeys, List> outKeys) { Dictionary> kset = new Dictionary>(); foreach (CmdKeyItem keyItem in inKeys) { if (!kset.ContainsKey(keyItem.KeysetId)) { kset.Add(keyItem.KeysetId, new List()); } kset[keyItem.KeysetId].Add(keyItem); } foreach (KeyValuePair> ksetGroup in kset) { PartitionByLength(maxKeys, ksetGroup.Value, outKeys); } } private static void PartitionByLength(int maxKeys, List inKeys, List> outKeys) { for (int i = 0; i < inKeys.Count; i += maxKeys) { outKeys.Add(inKeys.GetRange(i, Math.Min(maxKeys, inKeys.Count - i))); } } public static List> PartitionKeys(List inKeys) { CheckForDifferentKeyLengths(inKeys); List> outKeys = new List>(); PartitionByAlg(inKeys, outKeys); return outKeys; } } }