Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- private uint SearchID(string IP)
- {
- //преобразуем IP-адрес в беззнаковый UInt32
- uint ipn = IPConverter.IPToUInt32(IP);
- //получаем 1-й байт IP-адреса
- byte ip1n = (byte)(ipn / 0x1000000);
- //небольшая проверка
- if (ip1n == 0 || ip1n == 10 || ip1n == 127 ||
- ip1n >= Header.fbIndexLen)
- return 0;
- //достаем 3 младших байта
- uint ipn3b = (uint)(ipn - ip1n * 0x1000000);
- //находим блок данных в индексе первых байт
- uint blocks_min = fb_idx_arr[ip1n - 1];
- uint blocks_max = fb_idx_arr[ip1n];
- uint min = 0; uint max = 0;
- //если длина блока > кол-ва эл-тов в основном индексе
- if (blocks_max - blocks_min > Header.Range)
- {
- //ищем блок данных в основном индексе
- //При целочисленном делении результат
- //всегда округляется по направлению к нулю
- //Floor из оригинального исходника не нужен
- uint part = SearchIdx(ipn,blocks_min / Header.Range,
- (blocks_max / Header.Range)-1);
- // Нашли номер блока в котором нужно искать IP,
- // теперь находим нужный блок в БД
- min = part > 0 ? part * Header.Range : 0;
- max = part > Header.mIndexLen ? Header.DiapCount : (part + 1) * Header.Range;
- // Нужно проверить чтобы блок не выходил за
- // пределы блока первого байта
- if (min < blocks_min) min = blocks_min;
- if (max > blocks_max) max = blocks_max;
- }
- else
- {
- min = blocks_min;
- max = blocks_max;
- }
- uint len = max - min;
- uint ID = 0;
- //поиск в БД диапазонов
- if (DatabaseMode != SxGeoMode.FileMode) //БД диапазонов в памяти
- {
- ID = SearchDB(db_b, ipn3b, min, max);
- }
- else //БД диапазонов на диске
- {
- byte[] db_part = LoadDBPart(min, len);
- ID = SearchDB(db_part, ipn3b, 0, len);
- }
- return ID;
- }
- private uint SearchDB(byte[] db, uint ipn, uint min, uint max)
- {
- if (max - min > 1)
- {
- while (max - min > 8)
- {
- uint offset = (min + max) >> 1;
- uint x = getUintFrom3b(bSubstr(db, offset * Header.block_len, 3));
- if (ipn > getUintFrom3b(bSubstr(db, offset * Header.block_len, 3)))
- min = offset;
- else
- max = offset;
- }
- while (ipn >= getUintFrom3b(bSubstr(db, min * Header.block_len, 3))
- && ++min < max) { }
- }
- else
- {
- min++;
- }
- uint ans = 0;
- if (Header.IdLen == 3) //БД с городами
- {
- ans = getUintFrom3b(
- bSubstr(db, min * Header.block_len - Header.IdLen, Header.IdLen));
- }
- else //только ID стран
- {
- ans = bSubstr(db, min * Header.block_len - Header.IdLen, Header.IdLen)[0];
- }
- return ans;
- }
- //ищет блок данных в основном индексе
- private uint SearchIdx(uint ipn, uint min, uint max)
- {
- while (max - min > 8)
- {
- uint offset = (min + max) >> 1;
- if (ipn > m_idx_arr[offset])
- min = offset;
- else
- max = offset;
- }
- while (ipn > m_idx_arr[min] && min++ < max) { }
- return min;
- }
- //простой аналог substr для массива байт
- private byte[] bSubstr(byte[] Source, uint StartIndex, uint Length)
- {
- byte[] Dest = new byte[Length];
- Array.Copy(Source, StartIndex, Dest, 0, Length);
- return Dest;
- }
- //делает uint из 3 байтов
- //порядок входного массива BigEndian
- private uint getUintFrom3b(byte[] bytes)
- {
- byte[] buf = new byte[4];
- if (RevBO)
- {
- Array.Copy(bytes, 0, buf, 1, 3);
- Array.Reverse(buf);
- }
- else
- {
- Array.Copy(bytes, 0, buf, 0, 3);
- }
- return BitConverter.ToUInt32(buf, 0);
- }
- private byte[] LoadDBPart(uint min, uint len)
- {
- //перемещаемся на начало диапазонов +
- //найденное минимальное значение
- try
- {
- SxStream.Seek(Header.db_begin + min * Header.block_len,
- SeekOrigin.Begin);
- }
- catch (Exception ex)
- {
- ErrorMessage = ex.Message;
- return null;
- }
- return ReadBytes(SxStream, (int)(len * Header.block_len));
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement