-------------------------------------------------------------------------------- -- Title: IPLocation.lua -- Description: Like a square peg in a round hole -- Author: Raphaël Szwarc http://alt.textdrive.com/lua/ -- Creation Date: July 9, 2008 -- Legal: Copyright (C) 2007 Raphaël Szwarc -- Under the terms of the MIT License -- http://www.opensource.org/licenses/mit-license.html -------------------------------------------------------------------------------- -- import dependencies local io = require( 'io' ) local assert = assert local error = error local getmetatable = getmetatable local ipairs = ipairs local loadstring = loadstring local pcall = pcall local require = require local setmetatable = setmetatable local tonumber = tonumber local tostring = tostring -------------------------------------------------------------------------------- -- IPLocation -------------------------------------------------------------------------------- module( 'IPLocation' ) _VERSION = '1.0' local self = setmetatable( _M, {} ) local meta = getmetatable( self ) -------------------------------------------------------------------------------- -- DDL -------------------------------------------------------------------------------- local function Path( anExtension ) return ( '%s%s.%s' ):format( require( 'Bundle' )(), self._NAME, anExtension ) end local function Load( anExtension ) local aPath = Path( anExtension ) local aFile = assert( io.open( aPath, 'rb' ) ) local aContent = assert( aFile:read( '*a' ) ) local aContent = ( 'return { %s }' ):format( aContent ) local aChunk = assert( loadstring( aContent ) ) local aStatement = assert( aChunk() ) aFile:close() return aStatement end local DDL = Load( 'ddl' ) local DML = Load( 'dml' ) -------------------------------------------------------------------------------- -- DB -------------------------------------------------------------------------------- local function NewDB( aURL ) local aCall = function() local DB = require( 'DB' ) local aDB = DB( aURL ) for anIndex, aStatement in ipairs( DDL ) do aDB( aStatement ) end return aDB end local ok, aDB = pcall( aCall ) if ok then return aDB end end local function IPNumber( anAddress ) local anAddress = anAddress or '' local first, second, third, fourth = anAddress:match( '(%d+)%.(%d+)%.(%d+)%.(%d+)' ) if first and second and third and fourth then local aNumber = 0 aNumber = aNumber + tonumber( first ) * 16777216 aNumber = aNumber + tonumber( second ) * 65536 aNumber = aNumber + tonumber( third ) * 256 aNumber = aNumber + tonumber( fourth ) return aNumber end return 0 end local function FindLocation( aDB, anAddress ) if aDB then local aCall = function() local aNumber = IPNumber( anAddress ) local aCursor = aDB( DML[ 'FindLocation' ], aNumber ) local aRow = aCursor() aCursor.close = true if aRow and aNumber >= tonumber( aRow[ 'start' ] ) and aNumber <= tonumber( aRow[ 'end' ] ) then return aRow end end local ok, aResult = pcall( aCall ) if ok then return aResult end end end -------------------------------------------------------------------------------- -- Metamethods -------------------------------------------------------------------------------- local db = NewDB( 'sqlite3://localhost/' .. Path( 'db' ) ) function meta:__call( anAddress ) return IPNumber( anAddress ) end function meta:__index( aKey ) return FindLocation( db, aKey ) end function meta:__concat( aValue ) return tostring( self ) .. tostring( aValue ) end function meta:__tostring() return ( '%s/%s' ):format( self._NAME, self._VERSION ) end