)>}]
شركة التطبيقات المتكاملة لتصميم وبرمجة البرمجيات الخاصة ش.ش.و.
Integrated Applications Programming Company
Home » Code Library » Location (Ia.Cl.Models.Geography)

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