Reader.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Text;
  6. using Newtonsoft.Json;
  7. namespace TEAMModelOS.SDK.DI.IPIP
  8. {
  9. public class Reader
  10. {
  11. private readonly int fileSize;
  12. private readonly int nodeCount;
  13. private readonly MetaData meta;
  14. private readonly byte[] data;
  15. private readonly int v4offset;
  16. public Reader(string name)
  17. {
  18. var file = new FileInfo(name);
  19. fileSize = (int)file.Length;
  20. data = File.ReadAllBytes(name);
  21. var metaLength = bytesToLong(
  22. data[0],
  23. data[1],
  24. data[2],
  25. data[3]
  26. );
  27. var metaBytes = new byte[metaLength];
  28. Array.Copy(data, 4, metaBytes, 0, metaLength);
  29. var meta = JsonConvert.DeserializeObject<MetaData>(Encoding.UTF8.GetString(metaBytes));
  30. nodeCount = meta.nodeCount;
  31. this.meta = meta;
  32. if ((meta.totalSize + (int)metaLength + 4) != data.Length)
  33. {
  34. throw new InvalidDatabaseException("database file size error");
  35. }
  36. data = data.Skip((int)metaLength + 4).ToArray();
  37. if (v4offset == 0)
  38. {
  39. var node = 0;
  40. for (var i = 0; i < 96 && node < nodeCount; i++)
  41. {
  42. if (i >= 80)
  43. {
  44. node = readNode(node, 1);
  45. }
  46. else
  47. {
  48. node = readNode(node, 0);
  49. }
  50. }
  51. v4offset = node;
  52. }
  53. }
  54. public string[] find(string addr, string language)
  55. {
  56. int off;
  57. try
  58. {
  59. off = meta.Languages[language];
  60. }
  61. catch (NullReferenceException)
  62. {
  63. return null;
  64. }
  65. byte[] ipv;
  66. if (addr.IndexOf(":") > 0)
  67. {
  68. try
  69. {
  70. ipv = IPAddress.Parse(addr).GetAddressBytes();
  71. }
  72. catch (Exception)
  73. {
  74. return null;
  75. //throw new IPFormatException("ipv6 format error");
  76. }
  77. if ((meta.IPVersion & 0x02) != 0x02)
  78. {
  79. return null;
  80. //throw new IPFormatException("no support ipv6");
  81. }
  82. }
  83. else if (addr.IndexOf(".") > 0)
  84. {
  85. try
  86. {
  87. ipv = IPAddress.Parse(addr).GetAddressBytes();
  88. }
  89. catch (Exception)
  90. {
  91. return null;
  92. //throw new IPFormatException("ipv4 format error");
  93. }
  94. if ((meta.IPVersion & 0x01) != 0x01)
  95. {
  96. return null;
  97. //throw new IPFormatException("no support ipv4");
  98. }
  99. }
  100. else
  101. {
  102. return null;
  103. //throw new IPFormatException("ip format error");
  104. }
  105. int node;
  106. try
  107. {
  108. node = findNode(ipv);
  109. }
  110. catch (NotFoundException)
  111. {
  112. return null;
  113. }
  114. var data = resolve(node);
  115. var dst = new string[meta.Fields.Length];
  116. Array.Copy(data.Split('\t'), off, dst, 0, meta.Fields.Length);
  117. return dst;
  118. }
  119. private int findNode(byte[] binary)
  120. {
  121. var node = 0;
  122. var bit = binary.Length * 8;
  123. if (bit == 32)
  124. {
  125. node = v4offset;
  126. }
  127. for (var i = 0; i < bit; i++)
  128. {
  129. if (node > nodeCount)
  130. {
  131. break;
  132. }
  133. node = readNode(node, 1 & ((0xFF & binary[i / 8]) >> 7 - (i % 8)));
  134. }
  135. if (node > nodeCount)
  136. {
  137. return node;
  138. }
  139. throw new NotFoundException("ip not found");
  140. }
  141. private string resolve(int node)
  142. {
  143. var resoloved = node - nodeCount + nodeCount * 8;
  144. if (resoloved >= fileSize)
  145. {
  146. throw new InvalidDatabaseException("database resolve error");
  147. }
  148. byte b = 0;
  149. var size = (int)(bytesToLong(
  150. b,
  151. b,
  152. data[resoloved],
  153. data[resoloved + 1]
  154. ));
  155. if (data.Length < (resoloved + 2 + size))
  156. {
  157. throw new InvalidDatabaseException("database resolve error");
  158. }
  159. return Encoding.UTF8.GetString(data, resoloved + 2, size);
  160. }
  161. private int readNode(int node, int index)
  162. {
  163. var off = node * 8 + index * 4;
  164. return (int)(bytesToLong(
  165. data[off],
  166. data[off + 1],
  167. data[off + 2],
  168. data[off + 3]
  169. ));
  170. }
  171. private static long bytesToLong(byte a, byte b, byte c, byte d)
  172. {
  173. return int2long((((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff)));
  174. }
  175. private static long int2long(int i)
  176. {
  177. var l = i & 0x7fffffffL;
  178. if (i < 0)
  179. {
  180. l |= 0x080000000L;
  181. }
  182. return l;
  183. }
  184. public MetaData getMeta()
  185. {
  186. return meta;
  187. }
  188. public int getBuildUTCTime()
  189. {
  190. return meta.Build;
  191. }
  192. public string[] getSupportFields()
  193. {
  194. return meta.Fields;
  195. }
  196. }
  197. }