)>}]
شركة التطبيقات المتكاملة لتصميم وبرمجة البرمجيات الخاصة ش.ش.و.
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: 
  120:         /// <summary>
  121:         /// Distance between two coordinates in meters.
  122:         /// </summary>
  123:         public double GetDistanceTo(Location otherLocation)
  124:         {
  125:             double distance;
  126:             GeoCoordinate gc1, gc2;
  127: 
  128:             gc1 = new GeoCoordinate(this.Latitude, this.Longitude);
  129:             gc2 = new GeoCoordinate(otherLocation.Latitude, otherLocation.Longitude);
  130: 
  131:             distance = gc1.GetDistanceTo(gc2);
  132: 
  133:             return distance;
  134:         }
  135:         */
  136:  
  137:         ////////////////////////////////////////////////////////////////////////////
  138:  
  139:         /// <summary>
  140:         ///
  141:         /// </summary>
  142:         private static double DegreeToRadian(double angle)
  143:         {
  144:             return Math.PI * angle / 180.0;
  145:         }
  146:  
  147:         ////////////////////////////////////////////////////////////////////////////
  148:  
  149:         /// <summary>
  150:         ///
  151:         /// </summary>
  152:         private static double RadianToDegree(double angle)
  153:         {
  154:             return angle * (180.0 / Math.PI);
  155:         }
  156:  
  157:         ////////////////////////////////////////////////////////////////////////////
  158:  
  159:         /// <summary>
  160:         /// 
  161:         /// </summary>
  162:         public static string ReturnCMapValueForResolutionAndCoordinates(int resolution, double latitude, double longitude)
  163:         {
  164:             Location location;
  165:  
  166:             location = new Location(latitude, longitude);
  167:  
  168:             return location.ReturnCMapValueForResolution(resolution);
  169:         }
  170:  
  171:         ////////////////////////////////////////////////////////////////////////////
  172:  
  173:         /// <summary>
  174:         /// Converting latitude/longitude pairs to equivalent C-Squares
  175:         /// <remark ref="http://en.wikipedia.org/wiki/C-squares"/>
  176:         /// <remark ref="http://www.cmar.csiro.au/csquares/Point_java.txt"/>
  177:         /// </summary>
  178:         public string ReturnCMapValueForResolution(double resolution)
  179:         {
  180:             int i, j;
  181:             double llat, llon;
  182:             StringBuilder sb = new StringBuilder();
  183:  
  184:             if (latitude.DegreeDecimal >= 0)
  185:             {
  186:                 if (longitude.DegreeDecimal >= 0) sb.Append('1');
  187:                 else sb.Append('7');
  188:             }
  189:             else
  190:             {
  191:                 if (longitude.DegreeDecimal >= 0) sb.Append('3');
  192:                 else sb.Append('5');
  193:             }
  194:  
  195:             llat = Math.Abs(latitude.DegreeDecimal);
  196:  
  197:             if (llat >= 90) llat = 89.9;
  198:  
  199:             llon = Math.Abs(longitude.DegreeDecimal);
  200:  
  201:             if (llon >= 180) llon = 179.9;
  202:  
  203:             i = (int)(llat / 10);
  204:  
  205:             sb.Append(i);
  206:  
  207:             j = (int)(llon / 10);
  208:  
  209:             if (j < 10) sb.Append('0');
  210:  
  211:             sb.Append(j);
  212:  
  213:             if (resolution == 10)
  214:             {
  215:                 return sb.ToString();
  216:             }
  217:             else
  218:             {
  219:                 sb.Append(':');
  220:  
  221:                 llat -= i * 10;
  222:  
  223:                 llon -= j * 10;
  224:  
  225:                 i = (int)llat;
  226:  
  227:                 j = (int)llon;
  228:  
  229:                 if (i < 5)
  230:                 {
  231:                     if (j < 5) sb.Append('1');
  232:                     else sb.Append('2');
  233:                 }
  234:                 else
  235:                 {
  236:                     if (j < 5) sb.Append('3');
  237:                     else sb.Append('4');
  238:                 }
  239:  
  240:                 if (resolution == 5)
  241:                 {
  242:                     return sb.ToString();
  243:                 }
  244:                 else
  245:                 {
  246:                     sb.Append(i);
  247:  
  248:                     sb.Append(j);
  249:  
  250:                     if (resolution == 1)
  251:                     {
  252:                         return sb.ToString();
  253:                     }
  254:                     else
  255:                     {
  256:                         sb.Append(':');
  257:  
  258:                         i = (int)((llat - i) * 10);
  259:  
  260:                         j = (int)((llon - j) * 10);
  261:  
  262:                         if (i < 5)
  263:                         {
  264:                             if (j < 5) sb.Append('1');
  265:                             else sb.Append('2');
  266:                         }
  267:                         else
  268:                         {
  269:                             if (j < 5) sb.Append('3');
  270:                             else sb.Append('4');
  271:                         }
  272:  
  273:                         if (resolution == 0.5)
  274:                         {
  275:                             return sb.ToString();
  276:                         }
  277:                         else
  278:                         {
  279:                             sb.Append(i);
  280:                             sb.Append(j);
  281:  
  282:                             return sb.ToString();
  283:                         }
  284:                     }
  285:                 }
  286:             }
  287:         }
  288:  
  289:         ////////////////////////////////////////////////////////////////////////////
  290:         ////////////////////////////////////////////////////////////////////////////
  291:     }
  292:  
  293:  
  294:     ////////////////////////////////////////////////////////////////////////////
  295:     ////////////////////////////////////////////////////////////////////////////
  296:  
  297:     /// <summary>
  298:     ///
  299:     /// <remark ref="http://en.wikipedia.org/wiki/Geographic_coordinate_conversion"/>
  300:     /// </summary>
  301:     public class Coordinate
  302:     {
  303:         private double degreeDecimal;
  304:         private CoordinateType coordinateType { get; set; }
  305:  
  306:         private enum CoordinateType { Latitude, Longitude, Unknown };
  307:  
  308:         /// <summary/>
  309:         public bool IsNegative { get; set; }
  310:  
  311:         /// <summary/>
  312:         public int Degrees { get; set; }
  313:  
  314:         /// <summary/>
  315:         public int Minutes { get; set; }
  316:  
  317:         /// <summary/>
  318:         public int Seconds { get; set; }
  319:  
  320:         /// <summary/>
  321:         public int Milliseconds { get; set; }
  322:  
  323:         /*
  324:          * There are three basic forms of a coordinate.
  325:          * 
  326:          * Coordinate containing degrees (integer), minutes (integer), and seconds (integer, or real number) (DMS).
  327:          * Coordinate containing degrees (integer) and minutes (real number) (MinDec).
  328:          * Coordinate containing only degrees (real number) (DegDec).
  329:          * 
  330:          */
  331:  
  332:         ////////////////////////////////////////////////////////////////////////////
  333:  
  334:         /// <summary>
  335:         ///
  336:         /// </summary>
  337:         public Coordinate()
  338:         {
  339:         }
  340:  
  341:         ////////////////////////////////////////////////////////////////////////////
  342:  
  343:         /// <summary>
  344:         ///
  345:         /// </summary>
  346:         public Coordinate(double locationInDegreeDecimal)
  347:         {
  348:             degreeDecimal = locationInDegreeDecimal;
  349:  
  350:             // ensure the value will fall within the primary range [-180.0..+180.0]
  351:             while (locationInDegreeDecimal < -180.0) locationInDegreeDecimal += 360.0;
  352:  
  353:             while (locationInDegreeDecimal > 180.0) locationInDegreeDecimal -= 360.0;
  354:  
  355:             // switch the value to positive
  356:             IsNegative = locationInDegreeDecimal < 0;
  357:             locationInDegreeDecimal = Math.Abs(locationInDegreeDecimal);
  358:  
  359:             // gets the degree
  360:             Degrees = (int)Math.Floor(locationInDegreeDecimal);
  361:             var delta = locationInDegreeDecimal - Degrees;
  362:  
  363:             // gets minutes and seconds
  364:             var seconds = (int)Math.Floor(3600.0 * delta);
  365:             Seconds = seconds % 60;
  366:             Minutes = (int)Math.Floor(seconds / 60.0);
  367:             delta = delta * 3600.0 - seconds;
  368:  
  369:             // gets fractions
  370:             Milliseconds = (int)(1000.0 * delta);
  371:  
  372:             coordinateType = CoordinateType.Unknown;
  373:         }
  374:  
  375:         ////////////////////////////////////////////////////////////////////////////
  376:  
  377:         /// <summary>
  378:         ///
  379:         /// </summary>
  380:         public Coordinate(string locationInDegreeMinuteDecimalSecond)
  381:         {
  382:             double d;
  383:             string sign, r;
  384:             Match m;
  385:  
  386:             sign = "";
  387:  
  388:             /*
  389:              * All of the following are valid and acceptable ways to write geographic coordinates:
  390:              * 40°26'47"N 79°58'36"W
  391:              * 40°26′47″N 79°58′36″W
  392:              * 40:26:46N,79:56:55W
  393:              * 40:26:46.302N 79:56:55.903W
  394: 
  395:              * 40d 26′ 47″ N 79d 58′ 36″ W
  396:              * 40.446195N 79.948862W
  397:              * 40.446195, -79.948862
  398:              * 40° 26.7717, -79° 56.93172
  399:              */
  400:  
  401:             m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})°(\d{1,2})['′](.{1,})[""″]([NSEW])");
  402:  
  403:             if (m.Success) { }
  404:             else m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})[: ](\d{1,2})[: ](.{1,})([NSEW])");
  405:  
  406:             if (m.Success)
  407:             {
  408:                 try
  409:                 {
  410:                     Degrees = int.Parse(m.Groups[1].Captures[0].Value);
  411:                     Minutes = int.Parse(m.Groups[2].Captures[0].Value);
  412:  
  413:                     d = double.Parse(m.Groups[3].Captures[0].Value);
  414:  
  415:                     Seconds = (int)d;
  416:  
  417:                     d = d - Seconds;
  418:  
  419:                     Milliseconds = (int)(d * 1000);
  420:  
  421:                     // the sign
  422:                     sign = m.Groups[4].Captures[0].Value;
  423:                 }
  424:                 catch (Exception ex)
  425:                 {
  426: #if DEBUG
  427:                     r = "Error: " + ex.ToString();
  428: #else
  429:                     r = "Error: " + ex.Message;
  430: #endif
  431:                 }
  432:                 finally
  433:                 {
  434:                 }
  435:             }
  436:             else
  437:             {
  438:                 m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})°(\d{1,2})['′]([NSEW])");
  439:  
  440:                 if (m.Success) { }
  441:                 else m = Regex.Match(locationInDegreeMinuteDecimalSecond, @"(\d{1,3})[: ](\d{1,2})[: ]([NSEW])");
  442:  
  443:                 if (m.Success)
  444:                 {
  445:                     try
  446:                     {
  447:                         Degrees = int.Parse(m.Groups[1].Captures[0].Value);
  448:                         Minutes = int.Parse(m.Groups[2].Captures[0].Value);
  449:  
  450:                         Seconds = 0;
  451:                         Milliseconds = 0;
  452:  
  453:                         // the sign
  454:                         sign = m.Groups[3].Captures[0].Value;
  455:                     }
  456:                     catch (Exception ex)
  457:                     {
  458: #if DEBUG
  459:                         r = "Error: " + ex.ToString();
  460: #else
  461:                         r = "Error: " + ex.Message;
  462: #endif
  463:                     }
  464:                     finally
  465:                     {
  466:                     }
  467:                 }
  468:             }
  469:  
  470:             if (sign == "N" || sign == "E")
  471:             {
  472:                 IsNegative = false;
  473:                 coordinateType = CoordinateType.Latitude;
  474:             }
  475:             else if (sign == "S" || sign == "W")
  476:             {
  477:                 IsNegative = true;
  478:                 coordinateType = CoordinateType.Longitude;
  479:             }
  480:             else
  481:             {
  482:                 coordinateType = CoordinateType.Unknown;
  483:                 //throw new Exception();
  484:             }
  485:         }
  486:  
  487:         ////////////////////////////////////////////////////////////////////////////
  488:  
  489:         /// <summary>
  490:         ///
  491:         /// </summary>
  492:         public double DegreeDecimal
  493:         {
  494:             get
  495:             {
  496:                 double d;
  497:  
  498:                 //return degreeDecimal;
  499:  
  500:                 // Calculate the total number of seconds:
  501:                 d = Milliseconds / 1000.0 + Seconds + Minutes * 60;
  502:  
  503:                 // The fractional part is total number of seconds divided by 3600:
  504:                 d = d / 3600;
  505:  
  506:                 // Add fractional degrees to whole degrees to produce the final result:
  507:                 d = Degrees + d;
  508:  
  509:                 // switch the value to positive
  510:                 if (IsNegative) d = -d;
  511:  
  512:                 return Math.Round(d, 6);
  513:             }
  514:         }
  515:  
  516:         ////////////////////////////////////////////////////////////////////////////
  517:  
  518:         /// <summary>
  519:         ///
  520:         /// </summary>
  521:         public string DegreeMinuteSecond()
  522:         {
  523:             switch (coordinateType)
  524:             {
  525:                 case CoordinateType.Latitude:
  526:                     return string.Format(
  527:                         "{0}°{1:00}'{2:00}\"{3}",
  528:                         this.Degrees,
  529:                         this.Minutes,
  530:                         this.Seconds,
  531:                         this.IsNegative ? 'S' : 'N');
  532:  
  533:                 case CoordinateType.Longitude:
  534:                     return string.Format(
  535:                         "{0}°{1:00}'{2:00}\"{3}",
  536:                         this.Degrees,
  537:                         this.Minutes,
  538:                         this.Seconds,
  539:                         this.IsNegative ? 'W' : 'E');
  540:  
  541:                 default:
  542:                     return string.Format(
  543:                         "{0}°{1:00}'{2:00}\"",
  544:                         this.Degrees,
  545:                         this.Minutes,
  546:                         this.Seconds);
  547:             }
  548:         }
  549:  
  550:         ////////////////////////////////////////////////////////////////////////////
  551:  
  552:         /// <summary>
  553:         ///
  554:         /// </summary>
  555:         public string DegreeMinuteDecimalSecond()
  556:         {
  557:             switch (coordinateType)
  558:             {
  559:                 case CoordinateType.Latitude:
  560:                     return string.Format(
  561:                         "{0}°{1:00}'{2:00}.{3:000}\"{4}",
  562:                         this.Degrees,
  563:                         this.Minutes,
  564:                         this.Seconds,
  565:                         this.Milliseconds,
  566:                         this.IsNegative ? 'S' : 'N');
  567:  
  568:                 case CoordinateType.Longitude:
  569:                     return string.Format(
  570:                         "{0}°{1:00}'{2:00}.{3:000}\"{4}",
  571:                         this.Degrees,
  572:                         this.Minutes,
  573:                         this.Seconds,
  574:                         this.Milliseconds,
  575:                         this.IsNegative ? 'W' : 'E');
  576:  
  577:                 default:
  578:                     return string.Format(
  579:                         "{0}°{1:00}'{2:00}.{3:000}\"",
  580:                         this.Degrees,
  581:                         this.Minutes,
  582:                         this.Seconds,
  583:                         this.Milliseconds);
  584:             }
  585:         }
  586:  
  587:         ////////////////////////////////////////////////////////////////////////////
  588:  
  589:         /// <summary>
  590:         ///
  591:         /// </summary>
  592:         public string DegreeMinuteSecondDecimalMilliSecond()
  593:         {
  594:             switch (coordinateType)
  595:             {
  596:                 case CoordinateType.Latitude:
  597:                     return string.Format(
  598:                         "{0}°{1:00}'{2:00}\"0.{3:000}{4}",
  599:                         this.Degrees,
  600:                         this.Minutes,
  601:                         this.Seconds,
  602:                         this.Milliseconds,
  603:                         this.IsNegative ? 'S' : 'N');
  604:  
  605:                 case CoordinateType.Longitude:
  606:                     return string.Format(
  607:                         "{0}°{1:00}'{2:00}\"0.{3:000}{4}",
  608:                         this.Degrees,
  609:                         this.Minutes,
  610:                         this.Seconds,
  611:                         this.Milliseconds,
  612:                         this.IsNegative ? 'W' : 'E');
  613:  
  614:                 default:
  615:                     return string.Format(
  616:                         "{0}°{1:00}'{2:00}\"0.{3:000}",
  617:                         this.Degrees,
  618:                         this.Minutes,
  619:                         this.Seconds,
  620:                         this.Milliseconds);
  621:             }
  622:         }
  623:  
  624:         ////////////////////////////////////////////////////////////////////////////
  625:         ////////////////////////////////////////////////////////////////////////////
  626:     }
  627:  
  628:     ////////////////////////////////////////////////////////////////////////////
  629:     ////////////////////////////////////////////////////////////////////////////
  630:  
  631:     /* CountryLookup.cs
  632:      *
  633:      * Copyright (C) 2008 MaxMind, Inc.  All Rights Reserved.
  634:      *
  635:      * This library is free software; you can redistribute it and/or
  636:      * modify it under the terms of the GNU General Public
  637:      * License as published by the Free Software Foundation; either
  638:      * version 2 of the License, or (at your option) any later version.
  639:      *
  640:      * This library is distributed in the hope that it will be useful,
  641:      * but WITHOUT ANY WARRANTY; without even the implied warranty of
  642:      * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  643:      * General Public License for more details.
  644:      *
  645:      * You should have received a copy of the GNU General Public
  646:      * License along with this library; if not, write to the Free Software
  647:      * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  648:      */
  649:  
  650:     ////////////////////////////////////////////////////////////////////////////
  651:  
  652:     /// <summary>
  653:     ///
  654:     /// </summary>
  655:     public class GeoIp
  656:     {
  657:         private FileStream fileInput;
  658:         private long COUNTRY_BEGIN = 16776960;
  659:         private string[] countryCode =
  660:                                 { "--","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",
  661:                                     "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",
  662:                                     "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",
  663:                                     "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",
  664:                                     "O1","AX","GG","IM","JE","BL","MF"
  665:                                     };
  666:         private string[] countryName =
  667:                                 {"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",
  668:                                     "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",
  669:                                     "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)",
  670:                                     "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",
  671:                                     "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",
  672:                                     "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",
  673:                                     "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",
  674:                                     "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",
  675:                                     "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",
  676:                                     "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",
  677:                                     "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",
  678:                                     "Other","Aland Islands","Guernsey","Isle of Man","Jersey","Saint Barthelemy","Saint Martin"};
  679:  
  680:  
  681:         ////////////////////////////////////////////////////////////////////////////
  682:  
  683:         /// <summary>
  684:         ///
  685:         /// </summary>
  686:         public GeoIp(string fileName)
  687:         {
  688:             string path;
  689:  
  690:             try
  691:             {
  692:                 path = Ia.Cl.Model.Default.AbsolutePath();
  693:  
  694:                 fileInput = new FileStream(path + fileName, FileMode.Open, FileAccess.Read);
  695:             }
  696:             catch (FileNotFoundException)
  697:             {
  698:                 Console.WriteLine("File " + fileName + " not found");
  699:             }
  700:         }
  701:  
  702:         ////////////////////////////////////////////////////////////////////////////
  703:  
  704:         /// <summary>
  705:         ///
  706:         /// </summary>
  707:         public string LookupCountryCode(string str)
  708:         {
  709:             IPAddress addr;
  710:  
  711:             try
  712:             {
  713:                 addr = IPAddress.Parse(str);
  714:             }
  715:             catch (FormatException)
  716:             {
  717:                 return "--";
  718:             }
  719:  
  720:             return LookupCountryCode(addr);
  721:         }
  722:  
  723:         ////////////////////////////////////////////////////////////////////////////
  724:  
  725:         /// <summary>
  726:         ///
  727:         /// </summary>
  728:         private long IPAddressToNumber(IPAddress addr)
  729:         {
  730:             long ipnum = 0;
  731:             //byte[] b = BitConverter.GetBytes(addr.Address);
  732:             byte[] b = addr.GetAddressBytes();
  733:  
  734:             for (int i = 0; i < 4; ++i)
  735:             {
  736:                 long y = b[i];
  737:                 if (y < 0)
  738:                 {
  739:                     y += 256;
  740:                 }
  741:                 ipnum += y << ((3 - i) * 8);
  742:             }
  743:             Console.WriteLine(ipnum);
  744:             return ipnum;
  745:         }
  746:  
  747:         ////////////////////////////////////////////////////////////////////////////
  748:  
  749:         /// <summary>
  750:         ///
  751:         /// </summary>
  752:         public string LookupCountryCode(IPAddress addr)
  753:         {
  754:             return (countryCode[(int)SeekCountry(0, IPAddressToNumber(addr), 31)]);
  755:         }
  756:  
  757:         ////////////////////////////////////////////////////////////////////////////
  758:  
  759:         /// <summary>
  760:         ///
  761:         /// </summary>
  762:         public string LookupCountryName(string str)
  763:         {
  764:             IPAddress addr;
  765:             try
  766:             {
  767:                 addr = IPAddress.Parse(str);
  768:             }
  769:             catch (FormatException)
  770:             {
  771:                 return "N/A";
  772:             }
  773:             return LookupCountryName(addr);
  774:         }
  775:  
  776:         ////////////////////////////////////////////////////////////////////////////
  777:  
  778:         /// <summary>
  779:         ///
  780:         /// </summary>
  781:         public string LookupCountryName(IPAddress addr)
  782:         {
  783:             return (countryName[(int)SeekCountry(0, IPAddressToNumber(addr), 31)]);
  784:         }
  785:  
  786:         ////////////////////////////////////////////////////////////////////////////
  787:  
  788:         /// <summary>
  789:         ///
  790:         /// </summary>
  791:         private long SeekCountry(long offset, long ipnum, int depth)
  792:         {
  793:             byte[] buf = new byte[6];
  794:             long[] x = new long[2];
  795:             if (depth == 0)
  796:             {
  797:                 Console.WriteLine("Error seeking country.");
  798:             }
  799:  
  800:             try
  801:             {
  802:                 fileInput.Seek(6 * offset, 0);
  803:                 fileInput.Read(buf, 0, 6);
  804:             }
  805:             catch (IOException)
  806:             {
  807:                 Console.WriteLine("IO Exception");
  808:             }
  809:  
  810:             for (int i = 0; i < 2; i++)
  811:             {
  812:                 x[i] = 0;
  813:                 for (int j = 0; j < 3; j++)
  814:                 {
  815:                     int y = buf[i * 3 + j];
  816:                     if (y < 0)
  817:                     {
  818:                         y += 256;
  819:                     }
  820:                     x[i] += (y << (j * 8));
  821:                 }
  822:             }
  823:  
  824:             if ((ipnum & (1 << depth)) > 0)
  825:             {
  826:                 if (x[1] >= COUNTRY_BEGIN)
  827:                 {
  828:                     return x[1] - COUNTRY_BEGIN;
  829:                 }
  830:                 return SeekCountry(x[1], ipnum, depth - 1);
  831:             }
  832:             else
  833:             {
  834:                 if (x[0] >= COUNTRY_BEGIN)
  835:                 {
  836:                     return x[0] - COUNTRY_BEGIN;
  837:                 }
  838:                 return SeekCountry(x[0], ipnum, depth - 1);
  839:             }
  840:         }
  841:  
  842:         ////////////////////////////////////////////////////////////////////////////
  843:         ////////////////////////////////////////////////////////////////////////////
  844:     }
  845: }