Advertisement
tolikpunkoff

All search functions for SxGeoSharp

Sep 23rd, 2018
604
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.83 KB | None | 0 0
  1. private uint SearchID(string IP)
  2. {            
  3.     //преобразуем IP-адрес в беззнаковый UInt32
  4.     uint ipn = IPConverter.IPToUInt32(IP);
  5.     //получаем 1-й байт IP-адреса
  6.     byte ip1n = (byte)(ipn / 0x1000000);
  7.     //небольшая проверка
  8.     if (ip1n == 0 || ip1n == 10 || ip1n == 127 ||
  9.         ip1n >= Header.fbIndexLen)
  10.         return 0;
  11.                
  12.     //достаем 3 младших байта            
  13.     uint ipn3b = (uint)(ipn - ip1n * 0x1000000);
  14.  
  15.     //находим блок данных в индексе первых байт
  16.     uint blocks_min = fb_idx_arr[ip1n - 1];
  17.     uint blocks_max = fb_idx_arr[ip1n];
  18.     uint min = 0; uint max = 0;
  19.  
  20.     //если длина блока > кол-ва эл-тов в основном индексе
  21.     if (blocks_max - blocks_min > Header.Range)
  22.     {
  23.         //ищем блок данных в основном индексе
  24.         //При целочисленном делении результат
  25.         //всегда округляется по направлению к нулю
  26.         //Floor из оригинального исходника не нужен
  27.         uint part = SearchIdx(ipn,blocks_min / Header.Range,
  28.                         (blocks_max / Header.Range)-1);
  29.  
  30.         // Нашли номер блока в котором нужно искать IP,
  31.         // теперь находим нужный блок в БД
  32.         min = part > 0 ? part * Header.Range : 0;
  33.         max = part > Header.mIndexLen ? Header.DiapCount : (part + 1) * Header.Range;
  34.  
  35.         // Нужно проверить чтобы блок не выходил за
  36.         // пределы блока первого байта
  37.         if (min < blocks_min) min = blocks_min;
  38.         if (max > blocks_max) max = blocks_max;
  39.     }
  40.     else
  41.     {
  42.         min = blocks_min;
  43.         max = blocks_max;
  44.     }
  45.     uint len = max - min;
  46.  
  47.     uint ID = 0;
  48.     //поиск в БД диапазонов
  49.     if (DatabaseMode != SxGeoMode.FileMode) //БД диапазонов в памяти
  50.     {
  51.         ID = SearchDB(db_b, ipn3b, min, max);
  52.     }
  53.     else //БД диапазонов на диске
  54.     {
  55.         byte[] db_part = LoadDBPart(min, len);
  56.         ID = SearchDB(db_part, ipn3b, 0, len);
  57.     }
  58.  
  59.     return ID;
  60. }
  61.  
  62. private uint SearchDB(byte[] db, uint ipn, uint min, uint max)
  63. {            
  64.     if (max - min > 1)
  65.     {
  66.         while (max - min > 8)
  67.         {
  68.             uint offset = (min + max) >> 1;
  69.             uint x = getUintFrom3b(bSubstr(db, offset * Header.block_len, 3));
  70.             if (ipn > getUintFrom3b(bSubstr(db, offset * Header.block_len, 3)))
  71.                 min = offset;
  72.             else
  73.                 max = offset;                    
  74.         }
  75.  
  76.         while (ipn >= getUintFrom3b(bSubstr(db, min * Header.block_len, 3))
  77.             && ++min < max) { }
  78.     }
  79.     else
  80.     {
  81.         min++;
  82.     }
  83.  
  84.     uint ans = 0;
  85.  
  86.     if (Header.IdLen == 3) //БД с городами
  87.     {
  88.         ans = getUintFrom3b(
  89.             bSubstr(db, min * Header.block_len - Header.IdLen, Header.IdLen));
  90.     }
  91.     else //только ID стран
  92.     {
  93.         ans = bSubstr(db, min * Header.block_len - Header.IdLen, Header.IdLen)[0];
  94.     }
  95.  
  96.     return ans;
  97. }
  98.  
  99.  
  100. //ищет блок данных в основном индексе
  101. private uint SearchIdx(uint ipn, uint min, uint max)
  102. {
  103.     while (max - min > 8)
  104.     {
  105.         uint offset = (min + max) >> 1;
  106.         if (ipn > m_idx_arr[offset])
  107.             min = offset;
  108.         else
  109.             max = offset;
  110.     }
  111.  
  112.     while (ipn > m_idx_arr[min] && min++ < max) { }
  113.    
  114.     return min;
  115. }
  116.  
  117. //простой аналог substr для массива байт
  118. private byte[] bSubstr(byte[] Source, uint StartIndex, uint Length)
  119. {
  120.     byte[] Dest = new byte[Length];
  121.     Array.Copy(Source, StartIndex, Dest, 0, Length);
  122.     return Dest;
  123. }
  124.  
  125. //делает uint из 3 байтов
  126. //порядок входного массива BigEndian
  127. private uint getUintFrom3b(byte[] bytes)
  128. {
  129.     byte[] buf = new byte[4];
  130.     if (RevBO)
  131.     {
  132.         Array.Copy(bytes, 0, buf, 1, 3);
  133.         Array.Reverse(buf);
  134.     }
  135.     else
  136.     {
  137.         Array.Copy(bytes, 0, buf, 0, 3);
  138.     }
  139.     return BitConverter.ToUInt32(buf, 0);
  140. }
  141.  
  142.  
  143. private byte[] LoadDBPart(uint min, uint len)
  144. {
  145.     //перемещаемся на начало диапазонов +
  146.     //найденное минимальное значение
  147.  
  148.     try
  149.     {
  150.         SxStream.Seek(Header.db_begin + min * Header.block_len,
  151.             SeekOrigin.Begin);
  152.     }
  153.     catch (Exception ex)
  154.     {
  155.         ErrorMessage = ex.Message;
  156.         return null;
  157.     }
  158.  
  159.     return ReadBytes(SxStream, (int)(len * Header.block_len));
  160. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement