Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#

Optimized IP to ISO3166 Country Code Mapping in C#

Rate me:
Please Sign up or sign in to vote.
4.91/5 (72 votes)
12 Feb 200310 min read 226.8K   5.4K   120  
A .Net class that converts an IP Address to the Country Code where the computer is physically located.
/*
 * GameWatch - Server Browser for online games
 * Copyright (C) 2003 Rodrigo Reyes <reyes@charabia.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 */
using System;
using System.Collections;

namespace GameWatch.Utils.Net
{

    public class BitVectorTrie
    {
	public class Node
	{
	    public ArrayList Children = null;
	    public BitVector Key = null;
	    public Object Data = null;
	}

	public Node Root = new Node();
	
	public BitVectorTrie()
	{
	}

	public void Add(BitVector key, object data)
	{
	    Add(Root, key, data);
	}

	//
	// This Add method attach an object "data" to a node "n" using
	// the BitVector key as path.
	//
	private void Add(Node n, BitVector key, object data)
	{
	    if (n.Key == null)
		{
		    AddAsChildren(n, key, data);
		    return;
		}

	    //
	    // First, calculate the longest common prefix for the key
	    // and the BitVector stored in this node.
	    //
	    int longest = key.LongestCommonPrefix(n.Key);

	    System.Diagnostics.Debug.Assert(longest != 0);

	    if (longest == n.Key.Length)
		{
		    //
		    // If the current node is a perfect prefix of the
		    // key, then remove the prefix from the key, and
		    // we continue our walk on the children.
		    //
		    key = key.Range(longest, key.Length - longest);
		    AddAsChildren(n, key, data);
		    return;
		}
	    else
		{
		    //
		    // Here, n.Key and key share a common prefix. So we:
		    //
		    // - Create a new node with this common prefix
		    //   held there,
		    //
		    // - make n.Key and a new node with key as
		    // children of this new node.
		    BitVector common = n.Key.Range(0, longest);

		    Node c1 = new Node();
		    c1.Key = n.Key.Range(longest, n.Key.Length - longest);
		    c1.Data = n.Data;
		    c1.Children = n.Children;

		    Node c2 = new Node();
		    c2.Key = key.Range(longest, key.Length - longest);
		    c2.Data = data;
		    
		    n.Key = common;
		    n.Data = null;
		    n.Children = new ArrayList();
		    n.Children.Add(c1);
		    n.Children.Add(c2);

		    return;
		}
	}

	//
	// The AddAsChildren() method create a new node with key
	// "key", attach a data "data" to it, and finally link it to
	// the node "n".
	//
	private void AddAsChildren(Node n, BitVector key, Object data)
	{
	    //
	    // If "n" has no children, just add a new one
	    //
	    if (n.Children == null)
		{
		    n.Children = new ArrayList();
		    Node nu = new Node();
		    nu.Key = key;
		    nu.Data = data;
		    n.Children.Add(nu);
		    return;
		}

	    //
	    // From here, the node n already has at least 1
	    // children.


	    /// Check the one that has a common prefix with our key
	    //(if there is none, the bestindex variable stays at -1).

	    int bestindex = -1;
	    int bestlength = 0;
	    for (int i=0; i<n.Children.Count; i++)
		{
		    int b = ((Node)(n.Children[i])).Key.LongestCommonPrefix(key);

		    if (b > bestlength)
			{
			    bestlength = b;
			    bestindex = i;
			}
		}

	    //
	    // The node n has no children that have a common prefix
	    // with our key, so we create a new children node and
	    // attach our data there.
	    if (bestindex == -1)
		{
		    Node c2 = new Node();
		    c2.Key = key;
		    c2.Data = data;
		    n.Children.Add(c2);
		    return;
		}
	    else
		{
		    // There is a children node that can hold our
		    // data: continue our walk with this node.
		    Add(((Node)n.Children[bestindex]), key, data);
		    return;
		}
	}

	public object Get(BitVector key)
	{
	    Node curnode = Root;
	    while (curnode != null)
		{
		    if (curnode.Children == null)
			return null;

		    // Get the best fitting index
		    int bestindex = -1;
		    int bestlength = 0;
		    for (int i=0; i<curnode.Children.Count; i++)
			{
			    int b = ((Node)(curnode.Children[i])).Key.LongestCommonPrefix(key);
			    if (b > bestlength)
				{
				    bestlength = b;
				    bestindex = i;
				}
			}
		    
		    if (bestindex != -1)
			{
			    key = key.Range(bestlength, key.Length - bestlength);
			    curnode = ((Node)curnode.Children[bestindex]);

			    if (key.Length == 0)
				return curnode.Data;
			}
		    else
			{
			    return null;
			}
		}

	    return null;
	}

	//
	// Returns the object held in the node that best matches our
	// key.
	//
	public object GetBest(BitVector key)
	{
	    Node curnode = Root;
	    while (curnode != null)
		{
		    if (curnode.Children == null)
			return curnode.Data;

		    // Get the best fitting index
		    int bestindex = -1;
		    int bestlength = 0;
		    for (int i=0; i<curnode.Children.Count; i++)
			{
			    int b = ((Node)(curnode.Children[i])).Key.LongestCommonPrefix(key);
			    if (b > bestlength)
				{
				    bestlength = b;
				    bestindex = i;
				}
			}
		    
		    if (bestindex != -1)
			{
			    key = key.Range(bestlength, key.Length - bestlength);
			    curnode = ((Node)curnode.Children[bestindex]);

			    if (key.Length == 0)
				return curnode.Data;
			}
		    else
			{
			    return curnode.Data;
			}
		}

	    return null;
	}

	public void DisplayAsTree(Node n, int offset)
	{
	    for (int i=0; i<offset; i++)
		Console.Write("   ");
	    Console.WriteLine("<{0}> = <{1}>", n.Key, n.Data);
	    if (n.Children != null)
		{
		    foreach(Node c in n.Children)
			{
			    DisplayAsTree(c, offset+1);
			}
		}
	}

	static public void Test()
	{
	    BitVector.Test();
	    BitVectorTrie trie = new BitVectorTrie();
	    BitVector v1 = new BitVector();
	    v1.Set(0, true); // v1.Set(1, false);  v1.Set(2, true);
	    trie.Add(v1, "1");

	    v1 = new BitVector();
	    v1.Set(0, false); // v1.Set(1, false);  v1.Set(2, true);
	    trie.Add(v1, "0");

 	    v1 = new BitVector();
 	    v1.Set(0, false); v1.Set(1, false);  //v1.Set(2, false);
 	    trie.Add(v1, "00");

 	    v1 = new BitVector();
 	    v1.Set(0, true); v1.Set(1, true);  //v1.Set(2, false);
 	    trie.Add(v1, "11");

 	    v1 = new BitVector();
 	    v1.Set(0, false); v1.Set(1, true);  v1.Set(2, true);
 	    trie.Add(v1, "011");

	    v1 = new BitVector(255, 8);
 	    trie.Add(v1, "255");

	    v1 = new BitVector(1025, 11);
 	    trie.Add(v1, "1024");

	    v1 = new BitVector(1153, 11);
 	    trie.Add(v1, "1024+1+128");

	    trie.DisplayAsTree(trie.Root, 0);
	    v1 = new BitVector(1025, 11);
	    object result = trie.Get(v1);
	    Console.WriteLine("data: {0} = {1}", v1, result);

	}

    }


    

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions