KFDtool/sw/control/KFDtool.P25/Partition/KeyPartitioner.cs

157 lines
4.8 KiB
C#

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<CmdKeyItem> inKeys)
{
Dictionary<int, int> len = new Dictionary<int, int>();
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<CmdKeyItem> inKeys, List<List<CmdKeyItem>> outKeys)
{
Dictionary<int, List<CmdKeyItem>> alg = new Dictionary<int, List<CmdKeyItem>>();
foreach (CmdKeyItem keyItem in inKeys)
{
if (!alg.ContainsKey(keyItem.AlgorithmId))
{
alg.Add(keyItem.AlgorithmId, new List<CmdKeyItem>());
}
alg[keyItem.AlgorithmId].Add(keyItem);
}
foreach (KeyValuePair<int, List<CmdKeyItem>> algGroup in alg)
{
int maxKeys = CalcMaxKeysPerKmm(algGroup.Value[0].Key.Count);
PartitionByType(maxKeys, algGroup.Value, outKeys);
}
}
private static void PartitionByType(int maxKeys, List<CmdKeyItem> inKeys, List<List<CmdKeyItem>> outKeys)
{
List<CmdKeyItem> tek = new List<CmdKeyItem>();
List<CmdKeyItem> kek = new List<CmdKeyItem>();
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<CmdKeyItem> inKeys, List<List<CmdKeyItem>> outKeys)
{
List<CmdKeyItem> act = new List<CmdKeyItem>();
List<CmdKeyItem> def = new List<CmdKeyItem>();
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<CmdKeyItem> inKeys, List<List<CmdKeyItem>> outKeys)
{
Dictionary<int, List<CmdKeyItem>> kset = new Dictionary<int, List<CmdKeyItem>>();
foreach (CmdKeyItem keyItem in inKeys)
{
if (!kset.ContainsKey(keyItem.KeysetId))
{
kset.Add(keyItem.KeysetId, new List<CmdKeyItem>());
}
kset[keyItem.KeysetId].Add(keyItem);
}
foreach (KeyValuePair<int, List<CmdKeyItem>> ksetGroup in kset)
{
PartitionByLength(maxKeys, ksetGroup.Value, outKeys);
}
}
private static void PartitionByLength(int maxKeys, List<CmdKeyItem> inKeys, List<List<CmdKeyItem>> outKeys)
{
for (int i = 0; i < inKeys.Count; i += maxKeys)
{
outKeys.Add(inKeys.GetRange(i, Math.Min(maxKeys, inKeys.Count - i)));
}
}
public static List<List<CmdKeyItem>> PartitionKeys(List<CmdKeyItem> inKeys)
{
CheckForDifferentKeyLengths(inKeys);
List<List<CmdKeyItem>> outKeys = new List<List<CmdKeyItem>>();
PartitionByAlg(inKeys, outKeys);
return outKeys;
}
}
}