/src/Raven.Server/Documents/Indexes/Persistence/Lucene/Analyzers/Collation/CollationKeyFilter.cs

https://github.com/fitzchak/ravendb · C# · 139 lines · 108 code · 26 blank · 5 comment · 12 complexity · 1bccb44c392bbce799c2eb6732e6cd4b MD5 · raw file

  1. //-----------------------------------------------------------------------
  2. // <copyright file="CollationKeyFilter.cs" company="Hibernating Rhinos LTD">
  3. // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4. // </copyright>
  5. //-----------------------------------------------------------------------
  6. using System;
  7. using System.ComponentModel;
  8. using System.Globalization;
  9. using System.Linq.Expressions;
  10. using System.Runtime.InteropServices;
  11. using System.Security;
  12. using Lucene.Net.Analysis;
  13. using Lucene.Net.Analysis.Tokenattributes;
  14. using Sparrow.Platform;
  15. namespace Raven.Server.Documents.Indexes.Persistence.Lucene.Analyzers.Collation
  16. {
  17. public class CollationKeyFilter : TokenFilter
  18. {
  19. private readonly TermAttribute _termAtt;
  20. private readonly CultureInfo _cultureInfo;
  21. public CollationKeyFilter(TokenStream input, CultureInfo cultureInfo) : base(input)
  22. {
  23. _cultureInfo = cultureInfo;
  24. _termAtt = (TermAttribute)AddAttribute<ITermAttribute>();
  25. }
  26. public override bool IncrementToken()
  27. {
  28. if (input.IncrementToken() == false)
  29. return false;
  30. var termBuffer = _termAtt.TermBuffer();
  31. var termText = new string(termBuffer, 0, _termAtt.TermLength());
  32. var collationKey = GetCollationKey(termText);
  33. var encodedLength = IndexableBinaryStringTools_UsingArrays.GetEncodedLength(collationKey);
  34. if (sizeof(int) > termBuffer.Length)
  35. termBuffer = _termAtt.ResizeTermBuffer(encodedLength);
  36. _termAtt.SetTermLength(encodedLength);
  37. IndexableBinaryStringTools_UsingArrays.Encode(collationKey, termBuffer);
  38. return true;
  39. }
  40. private byte[] GetCollationKey(string text)
  41. {
  42. if (PlatformDetails.RunningOnPosix)
  43. return GetCollationKeyPosix(text);
  44. return GetCollationKeyWin32(text);
  45. }
  46. private unsafe byte[] GetCollationKeyPosix(string text)
  47. {
  48. var sortHandle = PosixHelper.Instance.GetSortHandle(_cultureInfo.CompareInfo);
  49. var length = PosixNativeMethods.GetSortKey(sortHandle, text, text.Length, null, 0, CompareOptions.None);
  50. if (length == 0)
  51. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to GetSortKey for text=" + text);
  52. var sortKey = new byte[length];
  53. fixed (byte* pSortKey = sortKey)
  54. {
  55. length = PosixNativeMethods.GetSortKey(sortHandle, text, text.Length, pSortKey, sortKey.Length, CompareOptions.None);
  56. if (length == 0)
  57. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to GetSortKey for text=" + text);
  58. return sortKey;
  59. }
  60. }
  61. private unsafe byte[] GetCollationKeyWin32(string text)
  62. {
  63. var length = Win32NativeMethods.LCMapStringEx(_cultureInfo.CompareInfo.Name, Win32NativeMethods.LCMAP_SORTKEY, text, text.Length, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
  64. if (length == 0)
  65. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to GetSortKey for text=" + text);
  66. var sortKey = new byte[length];
  67. fixed (byte* pSortKey = sortKey)
  68. {
  69. length = Win32NativeMethods.LCMapStringEx(_cultureInfo.CompareInfo.Name, Win32NativeMethods.LCMAP_SORTKEY, text, text.Length, (IntPtr)pSortKey, sortKey.Length, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
  70. if (length == 0)
  71. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to GetSortKey for text=" + text);
  72. return sortKey;
  73. }
  74. }
  75. private static class Win32NativeMethods
  76. {
  77. public const uint LCMAP_SORTKEY = 0x00000400;
  78. [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
  79. public static extern int LCMapStringEx(
  80. string lpLocaleName,
  81. uint dwMapFlags,
  82. string lpSrcStr,
  83. int cchSrc,
  84. [Out] IntPtr lpDestStr,
  85. int cchDest,
  86. IntPtr lpVersionInformation,
  87. IntPtr lpReserved,
  88. IntPtr sortHandle);
  89. }
  90. private static class PosixNativeMethods
  91. {
  92. [SecurityCritical]
  93. [DllImport("System.Globalization.Native", CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortKey")]
  94. public static extern unsafe int GetSortKey(SafeHandle sortHandle, string str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options);
  95. }
  96. private sealed class PosixHelper
  97. {
  98. public delegate SafeHandle GetSortHandleDelegate(CompareInfo value);
  99. public static readonly PosixHelper Instance = new PosixHelper();
  100. public readonly GetSortHandleDelegate GetSortHandle;
  101. private PosixHelper()
  102. {
  103. GetSortHandle = CreateGetSortHandleMethod().Compile();
  104. }
  105. private static Expression<GetSortHandleDelegate> CreateGetSortHandleMethod()
  106. {
  107. var parameter = Expression.Parameter(typeof(CompareInfo), "value");
  108. var member = Expression.Field(parameter, "_sortHandle");
  109. return Expression.Lambda<GetSortHandleDelegate>(member, parameter);
  110. }
  111. }
  112. }
  113. }