شركة التطبيقات المتكاملة لتصميم النظم البرمجية الخاصة ش.ش.و.

Integrated Applications Programming Company

Skip Navigation LinksHome » Code Library » Location

Public general use code classes and xml files that we've compiled and used over the years:

Geographic location related function, location, coordinates (latitude, longitude), bearing, degree and radian conversions, CMap value for resolution, and country geographic info-IP from MaxMind.

   1:  using System;
   2:  using System.Device.Location;
   3:  using System.IO;
   4:  using System.Net;
   5:  using System.Text;
   6:  using System.Text.RegularExpressions;
   7:   
   8:  namespace Ia.Cl.Model.Geography
   9:  {
  10:      ////////////////////////////////////////////////////////////////////////////
  11:   
  12:      /// <summary publish="true">
  13:      /// Geographic location related function, location, coordinates (latitude, longitude), bearing, degree and radian conversions, CMap value for resolution, and country geographic info-IP from MaxMind.
  14:      /// </summary>
  15:      /// 
  16:      /// <see href="http://en.wikipedia.org/wiki/Geographic_coordinate_conversion"/>
  17:      /// 
  18:      /// <remarks> 
  19:      /// Copyright © 2001-2015 Jasem Y. Al-Shamlan (info@ia.com.kw), Integrated Applications - Kuwait. All Rights Reserved.
  20:      ///
  21:      /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
  22:      /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  23:      ///
  24:      /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  25:      /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  26:      /// 
  27:      /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
  28:      /// 
  29:      /// Copyright notice: This notice may not be removed or altered from any source distribution.
  30:      /// </remarks> 
  31:      public class Location
  32:      {
  33:          //private GeoCoordinate latitude2, longitude2;
  34:          private Coordinate latitude, longitude;
  35:   
  36:          private CoordinateType coordinateType { get; set; }
  37:   
  38:          private enum CoordinateType { Latitude, Longitude, Unknown };
  39:   
  40:          /// <summary/>
  41:          public double Latitude { get { return latitude.DegreeDecimal; } }
  42:   
  43:          /// <summary/>
  44:          public double Longitude { get { return longitude.DegreeDecimal; } }
  45:   
  46:          ////////////////////////////////////////////////////////////////////////////
  47:   
  48:          /// <summary>
  49:          ///
  50:          /// </summary>
  51:          public Location(double latitudeLocationInDegreeDecimal, double longitudeLocationInDegreeDecimal)
  52:          {
  53:              latitude = new Coordinate(latitudeLocationInDegreeDecimal);
  54:              longitude = new Coordinate(longitudeLocationInDegreeDecimal);
  55:          }
  56:   
  57:          ////////////////////////////////////////////////////////////////////////////
  58:   
  59:          /// <summary>
  60:          ///
  61:          /// </summary>
  62:          public Location(string latitudeLocationInDegreeMinuteDecimalSecond, string longitudeLocationInDegreeMinuteDecimalSecond)
  63:          {
  64:              latitude = new Coordinate(latitudeLocationInDegreeMinuteDecimalSecond);
  65:              longitude = new Coordinate(longitudeLocationInDegreeMinuteDecimalSecond);
  66:          }
  67:   
  68:          ////////////////////////////////////////////////////////////////////////////
  69:   
  70:          /// <summary>
  71:          ///
  72:          /// </summary>
  73:          public static double[] ConvertWgs84ToGoogleBing(double lat, double lon)
  74:          {
  75:              double x = lon * 20037508.34 / 180;
  76:              double y = Math.Log(Math.Tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
  77:              y = y * 20037508.34 / 180;
  78:   
  79:              return new double[] { x, y };
  80:          }
  81:   
  82:          ////////////////////////////////////////////////////////////////////////////
  83:   
  84:          /// <summary>
  85:          ///
  86:          /// </summary>
  87:          public static double[] ConvertGoogleBingToWgs84Mercator(double x, double y)
  88:          {
  89:              double lon = (x / 20037508.34) * 180;
  90:              double lat = (y / 20037508.34) * 180;
  91:   
  92:              lat = 180 / Math.PI * (2 * Math.Atan(Math.Exp(lat * Math.PI / 180)) - Math.PI / 2);
  93:   
  94:              return new double[] { lon, lat };
  95:          }
  96:   
  97:          ////////////////////////////////////////////////////////////////////////////
  98:   
  99:          /// <summary>
 100:          /// Accepts two coordinates in degrees.
 101:          /// </summary>
 102:          /// <returns>A double value in degrees from 0 to 360.</returns>
 103:          public static Double Bearing(Location coordinate1, Location coordinate2)
 104:          {
 105:              var latitude1 = DegreeToRadian(coordinate1.Latitude);
 106:              var latitude2 = DegreeToRadian(coordinate2.Latitude);
 107:   
 108:              var longitudeDifference = DegreeToRadian((coordinate2.Longitude - coordinate1.Longitude));
 109:   
 110:              var y = Math.Sin(longitudeDifference) * Math.Cos(latitude2);
 111:              var x = Math.Cos(latitude1) * Math.Sin(latitude2) -
 112:                      Math.Sin(latitude1) * Math.Cos(latitude2) * Math.Cos(longitudeDifference);
 113:   
 114:              return (RadianToDegree(Math.Atan2(y, x)) + 360) % 360;
 115:          }
 116:   
 117:          ////////////////////////////////////////////////////////////////////////////
 118:   
 119:          /// <summary>
 120:          /// Distance between two coordinates in meters.
 121:          /// </summary>
 122:          public double GetDistanceTo(Location otherLocation)
 123:          {
 124:              double distance;
 125:              GeoCoordinate gc1, gc2;
 126:   
 127:              gc1 = new GeoCoordinate(this.Latitude, this.Longitude);
 128:              gc2 = new GeoCoordinate(otherLocation.Latitude, otherLocation.Longitude);
 129:   
 130:              distance = gc1.GetDistanceTo(gc2);
 131:   
 132:              return distance;
 133:          }
 134:   
 135:          ////////////////////////////////////////////////////////////////////////////
 136:   
 137:          /// <summary>
 138:          ///
 139:          /// </summary>
 140:          private static double DegreeToRadian(double angle)
 141:          {
 142:              return Math.PI * angle / 180.0;
 143:          }
 144:   
 145:          ////////////////////////////////////////////////////////////////////////////
 146:   
 147:          /// <summary>
 148:          ///
 149:          /// </summary>
 150:          private static double RadianToDegree(double angle)
 151:          {
 152:              return angle * (180.0 / Math.PI);
 153:          }
 154:   
 155:          ////////////////////////////////////////////////////////////////////////////
 156:   
 157:          /// <summary>
 158:          /// 
 159:          /// </summary>
 160:          public static string ReturnCMapValueForResolutionAndCoordinates(int resolution, double latitude, double longitude)
 161:          {
 162:              Location location;
 163:   
 164:              location = new Location(latitude, longitude);
 165:   
 166:              return location.ReturnCMapValueForResolution(resolution);
 167:          }
 168:   
 169:          ////////////////////////////////////////////////////////////////////////////
 170:   
 171:          /// <summary>
 172:          /// Converting latitude/longitude pairs to equivalent C-Squares
 173:          /// <remark ref="http://en.wikipedia.org/wiki/C-squares"/>
 174:          /// <remark ref="http://www.cmar.csiro.au/csquares/Point_java.txt"/>
 175:          /// </summary>
 176:          public string ReturnCMapValueForResolution(double resolution)
 177:          {
 178:              int i, j;
 179:              double llat, llon;
 180:              StringBuilder sb = new StringBuilder();
 181:   
 182:              if (latitude.DegreeDecimal >= 0)
 183:              {
 184:                  if (longitude.DegreeDecimal >= 0) sb.Append('1');
 185:                  else sb.Append('7');
 186:              }
 187:              else
 188:              {
 189:                  if (longitude.DegreeDecimal >= 0) sb.Append('3');
 190:                  else sb.Append('5');
 191:              }
 192:   
 193:              llat = Math.Abs(latitude.DegreeDecimal);
 194:   
 195:              if (llat >= 90) llat = 89.9;
 196:   
 197:              llon = Math.Abs(longitude.DegreeDecimal);
 198:   
 199:              if (llon >= 180) llon = 179.9;
 200:   
 201:              i = (int)(llat / 10);
 202:   
 203:              sb.Append(i);
 204:   
 205:              j = (int)(llon / 10);
 206:   
 207:              if (j < 10) sb.Append('0');
 208:   
 209:              sb.Append(j);
 210:   
 211:              if (resolution == 10)
 212:              {
 213:                  return sb.ToString();
 214:              }
 215:              else
 216:              {
 217:                  sb.Append(':');
 218:   
 219:                  llat -= i * 10;
 220:   
 221:                  llon -= j * 10;
 222:   
 223:                  i = (int)llat;
 224:   
 225:                  j = (int)llon;
 226:   
 227:                  if (i < 5)
 228:                  {
 229:                      if (j < 5) sb.Append('1');
 230:                      else sb.Append('2');
 231:                  }
 232:                  else
 233:                  {
 234:                      if (j < 5) sb.Append('3');
 235:                      else sb.Append('4');
 236:                  }
 237:   
 238:                  if (resolution == 5)
 239:                  {
 240:                      return sb.ToString();
 241:                  }
 242:                  else
 243:                  {
 244:                      sb.Append(i);
 245:   
 246:                      sb.Append(j);
 247:   
 248:                      if (resolution == 1)
 249:                      {
 250:                          return sb.ToString();
 251:                      }
 252:                      else
 253:                      {
 254:                          sb.Append(':');
 255:   
 256:                          i = (int)((llat - i) * 10);
 257:   
 258:                          j = (int)((llon - j) * 10);
 259:   
 260:                          if (i < 5)
 261:                          {
 262:                              if (j < 5) sb.Append('1');
 263:                              else sb.Append('2');
 264:                          }
 265:                          else
 266:                          {
 267:                              if (j < 5) sb.Append('3');
 268:                              else sb.Append('4');
 269:                          }
 270:   
 271:                          if (resolution == 0.5)
 272:                          {
 273:                              return sb.ToString();
 274:                          }
 275:                          else
 276:                          {
 277:                              sb.Append(i);
 278:                              sb.Append(j);
 279:   
 280:                              return sb.ToString();
 281:                          }
 282:                      }
 283:                  }
 284:              }
 285:          }
 286:   
 287:          ////////////////////////////////////////////////////////////////////////////
 288:          ////////////////////////////////////////////////////////////////////////////
 289:      }
 290:   
 291:   
 292:      ////////////////////////////////////////////////////////////////////////////
 293:      ////////////////////////////////////////////////////////////////////////////
 294:   
 295:      /// <summary>
 296:      ///
 297:      /// <remark ref="http://en.wikipedia.org/wiki/Geographic_coordinate_conversion"/>
 298:      /// </summary>
 299:      public class Coordinate
 300:      {
 301:          private double degreeDecimal;
 302:          private CoordinateType coordinateType { get; set; }
 303:   
 304:          private enum CoordinateType { Latitude, Longitude, Unknown };
 305:   
 306:          /// <summary/>
 307:          public bool IsNegative { get; set; }
 308:   
 309:          /// <summary/>
 310:          public int Degrees { get; set; }
 311:   
 312:          /// <summary/>
 313:          public int Minutes { get; set; }
 314:   
 315:          /// <summary/>
 316:          public int Seconds { get; set; }
 317:   
 318:          /// <summary/>
 319:          public int Milliseconds { get; set; }
 320:   
 321:          /*
 322:           * There are three basic forms of a coordinate.
 323:           * 
 324:           * Coordinate containing degrees (integer), minutes (integer), and seconds (integer, or real number) (DMS).
 325:           * Coordinate containing degrees (integer) and minutes (real number) (MinDec).
 326:           * Coordinate containing only degrees (real number) (DegDec).
 327:           * 
 328:           */
 329:   
 330:          ////////////////////////////////////////////////////////////////////////////
 331:   
 332:          /// <summary>
 333:          ///
 334:          /// </summary>
 335:          public Coordinate()
 336:          {
 337:          }
 338:   
 339:          ////////////////////////////////////////////////////////////////////////////
 340:   
 341:          /// <summary>
 342:          ///
 343:          /// </summary>
 344:          public Coordinate(double locationInDegreeDecimal)
 345:          {
 346:              degreeDecimal = locationInDegreeDecimal;
 347:   
 348:              // ensure the value will fall within the primary range [-180.0..+180.0]
 349:              while (locationInDegreeDecimal < -180.0) locationInDegreeDecimal += 360.0;
 350:   
 351:              while (locationInDegreeDecimal > 180.0) locationInDegreeDecimal -= 360.0;
 352:   
 353:              // switch the value to positive
 354:              IsNegative = locationInDegreeDecimal < 0;
 355:              locationInDegreeDecimal = Math.Abs(locationInDegreeDecimal);
 356:   
 357:              // gets the degree
 358:              Degrees = (int)Math.Floor(locationInDegreeDecimal);
 359:              var delta = locationInDegreeDecimal - Degrees;
 360:   
 361:              // gets minutes and seconds
 362:              var seconds = (int)Math.Floor(3600.0 * delta);
 363:              Seconds = seconds % 60;
 364:              Minutes = (int)Math.Floor(seconds / 60.0);
 365:              delta = delta * 3600.0 - seconds;
 366:   
 367:              // gets fractions
 368:              Milliseconds = (int)(1000.0 * delta);
 369:   
 370:              coordinateType = CoordinateType.Unknown;
 371:          }
 372:   
 373:          ////////////////////////////////////////////////////////////////////////////
 374:   
 375:          /// <summary>
 376:          ///
 377:          /// </summary>
 378:          public Coordinate(string locationInDegreeMinuteDecimalSecond)
 379:          {
 380:              double d;
 381:              string sign, r;
 382:              Match m;
 383:   
 384:              sign = "";
 385:   
 386:              /*
 387:               * All of the following are valid and acceptable ways to write geographic coordinates:
 388:               * 40°26'47"N 79°58'36"W
 389:               * 40°26′47″N 79°58′36″W
 390:               * 40:26:46N,79:56:55W
 391:               * 40:26:46.302N 79:56:55.903W
 392:  
 393:               * 40d 26′ 47″ N 79d 58′ 36″ W
 394:               * 40.446195N 79.948862W
 395:               * 40.446195, -79.948862
 396:               * 40° 26.7717, -79° 56.93172
 397:               */
 398:   
 399:              m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})°(\d{1,2})['′](.{1,})[""″]([NSEW])");
 400:   
 401:              if (m.Success) { }
 402:              else m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})[: ](\d{1,2})[: ](.{1,})([NSEW])");
 403:   
 404:              if (m.Success)
 405:              {
 406:                  try
 407:                  {
 408:                      Degrees = int.Parse(m.Groups[1].Captures[0].Value);
 409:                      Minutes = int.Parse(m.Groups[2].Captures[0].Value);
 410:   
 411:                      d = double.Parse(m.Groups[3].Captures[0].Value);
 412:   
 413:                      Seconds = (int)d;
 414:   
 415:                      d = d - Seconds;
 416:   
 417:                      Milliseconds = (int)(d * 1000);
 418:   
 419:                      // the sign
 420:                      sign = m.Groups[4].Captures[0].Value;
 421:                  }
 422:                  catch (Exception ex)
 423:                  {
 424:  #if DEBUG
 425:                      r = "Error: " + ex.ToString();
 426:  #else
 427:                      r = "Error: " + ex.Message;
 428:  #endif
 429:                  }
 430:                  finally
 431:                  {
 432:                  }
 433:              }
 434:              else
 435:              {
 436:                  m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})°(\d{1,2})['′]([NSEW])");
 437:   
 438:                  if (m.Success) { }
 439:                  else m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})[: ](\d{1,2})[: ]([NSEW])");
 440:   
 441:                  if (m.Success)
 442:                  {
 443:                      try
 444:                      {
 445:                          Degrees = int.Parse(m.Groups[1].Captures[0].Value);
 446:                          Minutes = int.Parse(m.Groups[2].Captures[0].Value);
 447:   
 448:                          Seconds = 0;
 449:                          Milliseconds = 0;
 450:   
 451:                          // the sign
 452:                          sign = m.Groups[3].Captures[0].Value;
 453:                      }
 454:                      catch (Exception ex)
 455:                      {
 456:  #if DEBUG
 457:                          r = "Error: " + ex.ToString();
 458:  #else
 459:                          r = "Error: " + ex.Message;
 460:  #endif
 461:                      }
 462:                      finally
 463:                      {
 464:                      }
 465:                  }
 466:              }
 467:   
 468:              if (sign == "N" || sign == "E")
 469:              {
 470:                  IsNegative = false;
 471:                  coordinateType = CoordinateType.Latitude;
 472:              }
 473:              else if (sign == "S" || sign == "W")
 474:              {
 475:                  IsNegative = true;
 476:                  coordinateType = CoordinateType.Longitude;
 477:              }
 478:              else
 479:              {
 480:                  coordinateType = CoordinateType.Unknown;
 481:                  //throw new Exception();
 482:              }
 483:          }
 484:   
 485:          ////////////////////////////////////////////////////////////////////////////
 486:   
 487:          /// <summary>
 488:          ///
 489:          /// </summary>
 490:          public double DegreeDecimal
 491:          {
 492:              get
 493:              {
 494:                  double d;
 495:   
 496:                  //return degreeDecimal;
 497:   
 498:                  // Calculate the total number of seconds:
 499:                  d = Milliseconds / 1000.0 + Seconds + Minutes * 60;
 500:   
 501:                  // The fractional part is total number of seconds divided by 3600:
 502:                  d = d / 3600;
 503:   
 504:                  // Add fractional degrees to whole degrees to produce the final result:
 505:                  d = Degrees + d;
 506:   
 507:                  // switch the value to positive
 508:                  if (IsNegative) d = -d;
 509:   
 510:                  return Math.Round(d, 6);
 511:              }
 512:          }
 513:   
 514:          ////////////////////////////////////////////////////////////////////////////
 515:   
 516:          /// <summary>
 517:          ///
 518:          /// </summary>
 519:          public string DegreeMinuteSecond()
 520:          {
 521:              switch (coordinateType)
 522:              {
 523:                  case CoordinateType.Latitude:
 524:                      return string.Format(
 525:                          "{0}°{1:00}'{2:00}\"{3}",
 526:                          this.Degrees,
 527:                          this.Minutes,
 528:                          this.Seconds,
 529:                          this.IsNegative ? 'S' : 'N');
 530:   
 531:                  case CoordinateType.Longitude:
 532:                      return string.Format(
 533:                          "{0}°{1:00}'{2:00}\"{3}",
 534:                          this.Degrees,
 535:                          this.Minutes,
 536:                          this.Seconds,
 537:                          this.IsNegative ? 'W' : 'E');
 538:   
 539:                  default:
 540:                      return string.Format(
 541:                          "{0}°{1:00}'{2:00}\"",
 542:                          this.Degrees,
 543:                          this.Minutes,
 544:                          this.Seconds);
 545:              }
 546:          }
 547:   
 548:          ////////////////////////////////////////////////////////////////////////////
 549:   
 550:          /// <summary>
 551:          ///
 552:          /// </summary>
 553:          public string DegreeMinuteDecimalSecond()
 554:          {
 555:              switch (coordinateType)
 556:              {
 557:                  case CoordinateType.Latitude:
 558:                      return string.Format(
 559:                          "{0}°{1:00}'{2:00}.{3:000}\"{4}",
 560:                          this.Degrees,
 561:                          this.Minutes,
 562:                          this.Seconds,
 563:                          this.Milliseconds,
 564:                          this.IsNegative ? 'S' : 'N');
 565:   
 566:                  case CoordinateType.Longitude:
 567:                      return string.Format(
 568:                          "{0}°{1:00}'{2:00}.{3:000}\"{4}",
 569:                          this.Degrees,
 570:                          this.Minutes,
 571:                          this.Seconds,
 572:                          this.Milliseconds,
 573:                          this.IsNegative ? 'W' : 'E');
 574:   
 575:                  default:
 576:                      return string.Format(
 577:                          "{0}°{1:00}'{2:00}.{3:000}\"",
 578:                          this.Degrees,
 579:                          this.Minutes,
 580:                          this.Seconds,
 581:                          this.Milliseconds);
 582:              }
 583:          }
 584:   
 585:          ////////////////////////////////////////////////////////////////////////////
 586:   
 587:          /// <summary>
 588:          ///
 589:          /// </summary>
 590:          public string DegreeMinuteSecondDecimalMilliSecond()
 591:          {
 592:              switch (coordinateType)
 593:              {
 594:                  case CoordinateType.Latitude:
 595:                      return string.Format(
 596:                          "{0}°{1:00}'{2:00}\"0.{3:000}{4}",
 597:                          this.Degrees,
 598:                          this.Minutes,
 599:                          this.Seconds,
 600:                          this.Milliseconds,
 601:                          this.IsNegative ? 'S' : 'N');
 602:   
 603:                  case CoordinateType.Longitude:
 604:                      return string.Format(
 605:                          "{0}°{1:00}'{2:00}\"0.{3:000}{4}",
 606:                          this.Degrees,
 607:                          this.Minutes,
 608:                          this.Seconds,
 609:                          this.Milliseconds,
 610:                          this.IsNegative ? 'W' : 'E');
 611:   
 612:                  default:
 613:                      return string.Format(
 614:                          "{0}°{1:00}'{2:00}\"0.{3:000}",
 615:                          this.Degrees,
 616:                          this.Minutes,
 617:                          this.Seconds,
 618:                          this.Milliseconds);
 619:              }
 620:          }
 621:   
 622:          ////////////////////////////////////////////////////////////////////////////
 623:          ////////////////////////////////////////////////////////////////////////////
 624:      }
 625:   
 626:      ////////////////////////////////////////////////////////////////////////////
 627:      ////////////////////////////////////////////////////////////////////////////
 628:   
 629:      /* CountryLookup.cs
 630:       *
 631:       * Copyright (C) 2008 MaxMind, Inc.  All Rights Reserved.
 632:       *
 633:       * This library is free software; you can redistribute it and/or
 634:       * modify it under the terms of the GNU General Public
 635:       * License as published by the Free Software Foundation; either
 636:       * version 2 of the License, or (at your option) any later version.
 637:       *
 638:       * This library is distributed in the hope that it will be useful,
 639:       * but WITHOUT ANY WARRANTY; without even the implied warranty of
 640:       * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 641:       * General Public License for more details.
 642:       *
 643:       * You should have received a copy of the GNU General Public
 644:       * License along with this library; if not, write to the Free Software
 645:       * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 646:       */
 647:   
 648:      ////////////////////////////////////////////////////////////////////////////
 649:   
 650:      /// <summary>
 651:      ///
 652:      /// </summary>
 653:      public class GeoIp
 654:      {
 655:          private FileStream fileInput;
 656:          private long COUNTRY_BEGIN = 16776960;
 657:          private string[] countryCode =
 658:                                  { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN","AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ",
 659:                                      "EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","FX","GA","GB","GD","GE","GF","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ",
 660:                                      "LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA",
 661:                                      "RE","RO","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA","ZM","ME","ZW","A1","A2",
 662:                                      "O1","AX","GG","IM","JE","BL","MF"
 663:                                      };
 664:          private string[] countryName =
 665:                                  {"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles","Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados","Bangladesh","Belgium",
 666:                                      "Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia","Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the","Central African Republic","Congo","Switzerland","Cote D'Ivoire",
 667:                                      "Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica","Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic","Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji","Falkland Islands (Malvinas)",
 668:                                      "Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana","Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala","Guam","Guinea-Bissau","Guyana",
 669:                                      "Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia","Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan","Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis",
 670:                                      "Korea, Democratic People's Republic of","Korea, Republic of","Kuwait","Cayman Islands","Kazakstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania","Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar",
 671:                                      "Marshall Islands","Macedonia","Mali","Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives","Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua","Netherlands",
 672:                                      "Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia","Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau","Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia",
 673:                                      "Solomon Islands","Seychelles","Sudan","Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname","Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo",
 674:                                      "Thailand","Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan","Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines",
 675:                                      "Venezuela","Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa","Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider",
 676:                                      "Other","Aland Islands","Guernsey","Isle of Man","Jersey","Saint Barthelemy","Saint Martin"};
 677:   
 678:   
 679:          ////////////////////////////////////////////////////////////////////////////
 680:   
 681:          /// <summary>
 682:          ///
 683:          /// </summary>
 684:          public GeoIp(string fileName)
 685:          {
 686:              string path;
 687:   
 688:              try
 689:              {
 690:                  path = Ia.Cl.Model.Default.AbsolutePath();
 691:   
 692:                  fileInput = new FileStream(path + fileName, FileMode.Open, FileAccess.Read);
 693:              }
 694:              catch (FileNotFoundException)
 695:              {
 696:                  Console.WriteLine("File " + fileName + " not found");
 697:              }
 698:          }
 699:   
 700:          ////////////////////////////////////////////////////////////////////////////
 701:   
 702:          /// <summary>
 703:          ///
 704:          /// </summary>
 705:          public string LookupCountryCode(string str)
 706:          {
 707:              IPAddress addr;
 708:   
 709:              try
 710:              {
 711:                  addr = IPAddress.Parse(str);
 712:              }
 713:              catch (FormatException)
 714:              {
 715:                  return "--";
 716:              }
 717:   
 718:              return LookupCountryCode(addr);
 719:          }
 720:   
 721:          ////////////////////////////////////////////////////////////////////////////
 722:   
 723:          /// <summary>
 724:          ///
 725:          /// </summary>
 726:          private long IPAddressToNumber(IPAddress addr)
 727:          {
 728:              long ipnum = 0;
 729:              //byte[] b = BitConverter.GetBytes(addr.Address);
 730:              byte[] b = addr.GetAddressBytes();
 731:   
 732:              for (int i = 0; i < 4; ++i)
 733:              {
 734:                  long y = b[i];
 735:                  if (y < 0)
 736:                  {
 737:                      y += 256;
 738:                  }
 739:                  ipnum += y << ((3 - i) * 8);
 740:              }
 741:              Console.WriteLine(ipnum);
 742:              return ipnum;
 743:          }
 744:   
 745:          ////////////////////////////////////////////////////////////////////////////
 746:   
 747:          /// <summary>
 748:          ///
 749:          /// </summary>
 750:          public string LookupCountryCode(IPAddress addr)
 751:          {
 752:              return (countryCode[(int)SeekCountry(0, IPAddressToNumber(addr), 31)]);
 753:          }
 754:   
 755:          ////////////////////////////////////////////////////////////////////////////
 756:   
 757:          /// <summary>
 758:          ///
 759:          /// </summary>
 760:          public string LookupCountryName(string str)
 761:          {
 762:              IPAddress addr;
 763:              try
 764:              {
 765:                  addr = IPAddress.Parse(str);
 766:              }
 767:              catch (FormatException)
 768:              {
 769:                  return "N/A";
 770:              }
 771:              return LookupCountryName(addr);
 772:          }
 773:   
 774:          ////////////////////////////////////////////////////////////////////////////
 775:   
 776:          /// <summary>
 777:          ///
 778:          /// </summary>
 779:          public string LookupCountryName(IPAddress addr)
 780:          {
 781:              return (countryName[(int)SeekCountry(0, IPAddressToNumber(addr), 31)]);
 782:          }
 783:   
 784:          ////////////////////////////////////////////////////////////////////////////
 785:   
 786:          /// <summary>
 787:          ///
 788:          /// </summary>
 789:          private long SeekCountry(long offset, long ipnum, int depth)
 790:          {
 791:              byte[] buf = new byte[6];
 792:              long[] x = new long[2];
 793:              if (depth == 0)
 794:              {
 795:                  Console.WriteLine("Error seeking country.");
 796:              }
 797:   
 798:              try
 799:              {
 800:                  fileInput.Seek(6 * offset, 0);
 801:                  fileInput.Read(buf, 0, 6);
 802:              }
 803:              catch (IOException)
 804:              {
 805:                  Console.WriteLine("IO Exception");
 806:              }
 807:   
 808:              for (int i = 0; i < 2; i++)
 809:              {
 810:                  x[i] = 0;
 811:                  for (int j = 0; j < 3; j++)
 812:                  {
 813:                      int y = buf[i * 3 + j];
 814:                      if (y < 0)
 815:                      {
 816:                          y += 256;
 817:                      }
 818:                      x[i] += (y << (j * 8));
 819:                  }
 820:              }
 821:   
 822:              if ((ipnum & (1 << depth)) > 0)
 823:              {
 824:                  if (x[1] >= COUNTRY_BEGIN)
 825:                  {
 826:                      return x[1] - COUNTRY_BEGIN;
 827:                  }
 828:                  return SeekCountry(x[1], ipnum, depth - 1);
 829:              }
 830:              else
 831:              {
 832:                  if (x[0] >= COUNTRY_BEGIN)
 833:                  {
 834:                      return x[0] - COUNTRY_BEGIN;
 835:                  }
 836:                  return SeekCountry(x[0], ipnum, depth - 1);
 837:              }
 838:          }
 839:   
 840:          ////////////////////////////////////////////////////////////////////////////
 841:          ////////////////////////////////////////////////////////////////////////////
 842:      }
 843:  }