using System;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Jd.ACES.Common.Exceptions;
namespace Jd.ACES.Common
{
public class IndexCalculator
{
readonly static string LONG_PLACEHOLDER;
static IndexCalculator()
{
LONG_PLACEHOLDER = GeneratePlaceholderForNonAscii();
}
///
/// Computes hash value for the specified input and salt with SHA256 algorithm.
///
/// The byte array of input to compute.
/// The byte array of salt to compute.
/// The byte array of computed hash code.
/// Thrown when input is null.
/// Thrown when salt lenght is too short.
public static byte[] Sha256Index(byte[] input, byte[] salt)
{
if (input == null)
throw new ArgumentException("Input is null for sha256Index function.");
if (salt == null || salt.Length < Constants.MIN_SALT_LEN)
throw new InsufficientSaltLengthException("Salt length is too short.");
byte[] combined = new byte[input.Length + salt.Length];
// append input and salt together
Array.Copy(input, 0, combined, 0, input.Length);
Array.Copy(salt, 0, combined, input.Length, salt.Length);
using (SHA256 hash = SHA256.Create())
{
return hash.ComputeHash(combined);
}
}
static string GeneratePlaceholderForNonAscii()
{
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < 6; i++)
{
buffer.Append(WildcardPattern.ASCII);
}
return buffer.ToString();
}
///
/// Attempts to format the specified plaintext to unicode encoding.
///
/// The original plaintext to format.
/// formatted plaintext if the plaintext contains non-ASCII character.
public static string FormatPlaintext(string plaintext)
{
return UnicodeEncode(plaintext);
}
///
/// Attempts to format the query keyword to unicode encoding.
///
/// The original query keyword to format.
/// formatted keyword.
public static string FormatQueryKeyword(string keyword)
{
return FormatQueryKeyword(keyword, WildcardPattern.NON_ASCII);
}
///
/// Attempts to format the query keyword to unicode encoding.
/// Each placeholder for non-ASCII character, such as '#',
/// in keyword will be replaced with the long placeholder.
///
/// The original query keyword to format.
/// The placeholder for non-ASCII character.
/// formatted keyword.
public static string FormatQueryKeyword(string keyword, char placeholderForNonAscii)
{
keyword = UnicodeEncode(keyword);
if (!keyword.Contains(placeholderForNonAscii))
{
return keyword;
}
StringBuilder buffer = new StringBuilder();
for (int i = 0, len = keyword.Length; i < len; i++)
{
if (keyword[i] == placeholderForNonAscii)
{
buffer.Append(LONG_PLACEHOLDER);
}
else if (keyword[i] == WildcardPattern.ASCII)
{
buffer.Append(keyword[i]);
}
else
{
buffer.Append(keyword.Substring(i, keyword.Length - i));
break;
}
}
return buffer.ToString();
}
///
/// Encodes the specified non-ASCII string to unicode encoding.
///
/// The string to encode.
/// unicode encoding string.
public static string UnicodeEncode(string data)
{
if (IsPureAscii(data))
return data;
char[] utfBytes = data.ToCharArray();
StringBuilder buffer = new StringBuilder();
for (int byteIndex = 0, len = utfBytes.Length; byteIndex < len; byteIndex++)
{
if (IsPureAscii(utfBytes[byteIndex]))
{
buffer.Append(utfBytes[byteIndex]);
continue;
}
buffer.Append("\\u").AppendFormat("{0:x2}", (int)utfBytes[byteIndex]);
}
return buffer.ToString();
}
///
/// Decodes the specified unicode encoding string.
///
/// The string to decode.
/// decoded string.
public static string UnicodeDecode(string data)
{
StringBuilder buffer = new StringBuilder();
string charStr = "";
for (int i = 0, len = data.Length; i < len;)
{
int offset = data.IndexOf("\\u", i);
if (offset == -1 || offset + 6 > data.Length)
{
charStr = data.Substring(i, data.Length - i);
buffer.Append(charStr);
i = data.Length;
}
else
{
buffer.Append(data.Substring(i, offset - i));
charStr = data.Substring(offset + 2, 4);
string letter = Char.ConvertFromUtf32(Convert.ToInt32(charStr, 16));
buffer.Append(letter);
i = offset + 6;
}
}
return buffer.ToString();
}
public static bool IsPureAscii(char c)
{
return c >= 0 && c < 128;
}
public static bool IsPureAscii(string s)
{
return Encoding.UTF8.GetByteCount(s) == s.Length;
}
public static string GenerateWildcardKeyword(string keyword, int asciiCharPrefixNumber, int nonAsciiCharPrefixNumber)
{
int length = asciiCharPrefixNumber + nonAsciiCharPrefixNumber * 6;
if (length == 0)
{
return keyword;
}
StringBuilder buffer = new StringBuilder();
char[] prefix = Enumerable.Repeat(WildcardPattern.ASCII, length).ToArray();
return buffer.Append(prefix).Append(keyword).ToString();
}
}
public class WildcardPattern
{
public static char ASCII { get { return '*'; } }
public static char NON_ASCII { get { return '#'; } }
}
}