836 lines
24 KiB
Plaintext
836 lines
24 KiB
Plaintext
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
MAP.java
|
|
|
|
Abstract:
|
|
|
|
This module implements requests to MAP files.
|
|
|
|
Author:
|
|
|
|
Saurab Nog ( SaurabN ) 26-Apr-1999
|
|
|
|
Environment:
|
|
|
|
COM+ - User Mode Managed Run Time
|
|
|
|
Project:
|
|
|
|
Web Server
|
|
|
|
--*/
|
|
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Collections;
|
|
using System.ASP;
|
|
|
|
namespace System.IIS
|
|
{
|
|
|
|
public class MapHandler : IHttpHandler
|
|
{
|
|
//
|
|
// Point offset of x and y coordinates in a polygon
|
|
//
|
|
|
|
private const int X = 0;
|
|
private const int Y = 1;
|
|
|
|
//
|
|
// File Data
|
|
//
|
|
|
|
private char[] _fileContents = null;
|
|
private int _fileSize = 0;
|
|
|
|
//
|
|
// Indexes into various parts of the File Data
|
|
//
|
|
|
|
private int _index = 0;
|
|
private int _urlIndex = 0;
|
|
|
|
|
|
public void ProcessRequest(HttpContext context)
|
|
{
|
|
HttpRequest request = context.Request;
|
|
HttpResponse response = context.Response;
|
|
String QueryStr = request.Url.QueryString;
|
|
|
|
String TargetUrl = null;
|
|
String MapFileName = request.PhysicalPath;
|
|
|
|
char ch;
|
|
int x, y, index, QueryStrLength;
|
|
bool fxNegative = false, fyNegative = false;
|
|
|
|
//
|
|
// Get the x and y cooridinates of the mouse click on the image
|
|
//
|
|
|
|
QueryStrLength = QueryStr.Length;
|
|
|
|
x = 0;
|
|
index = 0;
|
|
|
|
if ((index < QueryStrLength) &&
|
|
(QueryStr[index] == '-'))
|
|
{
|
|
index++;
|
|
fxNegative = true;
|
|
}
|
|
|
|
while ((index < QueryStrLength) &&
|
|
CharacterInfo.IsDecimalDigit(ch = QueryStr[index]))
|
|
{
|
|
x = x*10 + (ch -'0');
|
|
index++;
|
|
}
|
|
|
|
if (fxNegative)
|
|
x = -x;
|
|
|
|
//
|
|
// Move past any intervening delimiters
|
|
//
|
|
|
|
while ((index < QueryStrLength) &&
|
|
( !CharacterInfo.IsDecimalDigit(QueryStr[index])) &&
|
|
( QueryStr[index] != '-'))
|
|
index++;
|
|
|
|
//
|
|
// Read y
|
|
//
|
|
|
|
y = 0;
|
|
|
|
if ((index < QueryStrLength) &&
|
|
(QueryStr[index] == '-'))
|
|
{
|
|
index++;
|
|
fyNegative = true;
|
|
}
|
|
|
|
while ( (index < QueryStrLength) &&
|
|
CharacterInfo.IsDecimalDigit(ch = QueryStr[index]) )
|
|
{
|
|
y = y*10 + (ch -'0');
|
|
index++;
|
|
}
|
|
|
|
if (fyNegative)
|
|
y = -y;
|
|
|
|
//
|
|
// Search for the coordinate (x,y) in the map file
|
|
//
|
|
|
|
try
|
|
{
|
|
// BUGBUG: Impersonate the user
|
|
TargetUrl = SearchMapFile( response,
|
|
MapFileName,
|
|
x,
|
|
y);
|
|
}
|
|
catch (SecurityException e)
|
|
{
|
|
throw new HttpException(HttpStatus.Unauthorized, "Could not access file", e);
|
|
}
|
|
catch (FileNotFoundException e)
|
|
{
|
|
throw new HttpException(HttpStatus.NotFound, "Could not find file", e);
|
|
}
|
|
catch (PathNotFoundException e)
|
|
{
|
|
throw new HttpException(HttpStatus.NotFound, "Could not find file", e);
|
|
}
|
|
catch(IOException e)
|
|
{
|
|
throw new HttpException(HttpStatus.Forbidden, "Cannot open file", e);
|
|
}
|
|
|
|
if (0 == TargetUrl.Length)
|
|
{
|
|
//
|
|
// No entry found
|
|
//
|
|
|
|
if (null != request.UrlReferrer)
|
|
{
|
|
//
|
|
// Redirect back to referrer
|
|
//
|
|
|
|
TargetUrl = request.UrlReferrer.ToString();
|
|
}
|
|
else
|
|
throw new HttpException(HttpStatus.NoContent, "Invalid map file");
|
|
}
|
|
|
|
//
|
|
// If the found URL starts with a forward slash ("/foo/bar/doc.htm")
|
|
// and it doesn't contain a bookmark ('#') then the URL is local and
|
|
// we build a fully qualified URL to send back to the client.
|
|
// we assume it's a fully qualified URL ("http://foo/bar/doc.htm")
|
|
// and send the client a redirection notice to the mapped URL
|
|
//
|
|
|
|
if ( 0 < TargetUrl.Length )
|
|
{
|
|
String RedirectUrl;
|
|
|
|
if ('/' == TargetUrl[0])
|
|
{
|
|
//
|
|
// Fully qualify the URL and send a redirect. Some
|
|
// browsers (eg mosaic) don't like doc relative URLs
|
|
// with bookmarks. NOTE: We fully qualify the URL with
|
|
// the protocol (http or https) based on the port this
|
|
// request came in on. This means you cannot have a
|
|
// partial URL with a bookmark (which is how we got
|
|
// here) go from a secure part of the server to a
|
|
// nonsecure part of the server.
|
|
//
|
|
|
|
// hack to get rid of the port number, if default
|
|
// Would have been easier if we had been able to call
|
|
// HttpUrl::IsDefaultPort()
|
|
String protocol = (request.IsSecureConnection) ? "https" : "http";
|
|
HttpUrl url = new HttpUrl(protocol, request.Url.Host, request.Url.Port, TargetUrl, null, null);
|
|
RedirectUrl = url.ToString();
|
|
}
|
|
else
|
|
RedirectUrl = TargetUrl;
|
|
|
|
response.Redirect(RedirectUrl);
|
|
}
|
|
}
|
|
|
|
private String SearchMapFile(HttpResponse response, String MapFileName,
|
|
int x, int y) {
|
|
FileStream fs;
|
|
bool fFound;
|
|
String TargetUrl = "";
|
|
byte[] Contents = null;
|
|
|
|
int PointUrlIndex = 0;
|
|
int DefaultUrlIndex = 0;
|
|
|
|
double MinDistanceFromPoint = Double.MaxValue;
|
|
|
|
//
|
|
// Open the file for use
|
|
//
|
|
|
|
fs = new FileStream (MapFileName,
|
|
FileMode.Open,
|
|
FileAccess.Read,
|
|
FileShare.Read);
|
|
|
|
//
|
|
// Read in the file contents into buffer
|
|
//
|
|
|
|
_fileSize = (int) fs.GetLength();
|
|
Contents = fs.ReadToEnd();
|
|
fs.Close();
|
|
|
|
|
|
Decoder dec = Encoding.GetASCII().GetDecoder();
|
|
_fileContents = new char[dec.GetCharCount(Contents, 0, _fileSize)];
|
|
|
|
dec.GetChars(Contents, 0, _fileSize, _fileContents, 0);
|
|
|
|
//
|
|
// Loop through the contents of the file and see what we've got
|
|
//
|
|
|
|
fFound = false;
|
|
_index = 0;
|
|
|
|
while ((_index < _fileSize) && !fFound)
|
|
{
|
|
switch (_fileContents[_index])
|
|
{
|
|
//
|
|
// Comment, skip the line
|
|
//
|
|
|
|
case '#':
|
|
break;
|
|
|
|
//
|
|
// Rectangle and Oval.
|
|
//
|
|
// BUGBUG handles oval as a rect, as they are using the same
|
|
// specification format. Should do better.
|
|
//
|
|
|
|
case 'r':
|
|
case 'o':
|
|
case 'R':
|
|
case 'O':
|
|
|
|
if ( (_index < (_fileSize - 4)) &&
|
|
((0 == Compare("rect", _fileContents, _index, 4)) ||
|
|
(0 == Compare("oval", _fileContents, _index, 4)))
|
|
)
|
|
{
|
|
_index += 4;
|
|
fFound = PointInRect( x, y);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Circle
|
|
//
|
|
|
|
case 'c':
|
|
case 'C':
|
|
|
|
if ( (_index < (_fileSize - 4)) &&
|
|
( 0 == Compare("circ", _fileContents, _index, 4))
|
|
)
|
|
{
|
|
_index += 4;
|
|
fFound = PointInCircle( x, y);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Polygon and Point
|
|
//
|
|
|
|
case 'p':
|
|
case 'P':
|
|
|
|
if ( (_index < (_fileSize - 4)) &&
|
|
( 0 == Compare("poly", _fileContents, _index, 4))
|
|
)
|
|
{
|
|
_index += 4;
|
|
fFound = PointInPoly( x, y);
|
|
|
|
}
|
|
else if ( (_index < (_fileSize - 5)) &&
|
|
( 0 == Compare("point", _fileContents, _index, 5))
|
|
)
|
|
{
|
|
double distance;
|
|
|
|
_index += 5;
|
|
distance = PointInPoint( x, y);
|
|
|
|
if ( distance < MinDistanceFromPoint)
|
|
{
|
|
MinDistanceFromPoint = distance;
|
|
PointUrlIndex = _urlIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Default URL
|
|
//
|
|
|
|
case 'd':
|
|
case 'D':
|
|
|
|
if ( (_index < (_fileSize - 3)) &&
|
|
( 0 == Compare("def", _fileContents, _index, 3))
|
|
)
|
|
{
|
|
_index += 3;
|
|
DefaultUrlIndex = GetDefaultUrl();
|
|
}
|
|
break;
|
|
} // switch
|
|
|
|
if ( !fFound )
|
|
SkipLine( );
|
|
|
|
} // while
|
|
|
|
//
|
|
// If we didn't find a mapping and a point or a default was specified,
|
|
// use that URL
|
|
//
|
|
|
|
if (!fFound)
|
|
{
|
|
if ( 0 != PointUrlIndex )
|
|
{
|
|
_urlIndex = PointUrlIndex;
|
|
fFound = true;
|
|
}
|
|
else if ( 0 != DefaultUrlIndex )
|
|
{
|
|
_urlIndex = DefaultUrlIndex;
|
|
fFound = true;
|
|
}
|
|
}
|
|
|
|
if (fFound)
|
|
{
|
|
//
|
|
// make _urlIndex point to the start of the URL
|
|
//
|
|
|
|
_index = _urlIndex;
|
|
|
|
SkipWhiteExceptNewLine();
|
|
|
|
_urlIndex = _index;
|
|
|
|
//
|
|
// Determine the length of the URL and copy it out
|
|
//
|
|
|
|
SkipNonWhite();
|
|
|
|
TargetUrl = new String(_fileContents, _urlIndex, _index - _urlIndex);
|
|
|
|
//
|
|
// BUGBUG - Escape the URL
|
|
//
|
|
|
|
Util.Debug.Trace("SearchMapFile",
|
|
"Mapping for " + x.ToString() +
|
|
"," + y.ToString() + " is :" + TargetUrl + "\n");
|
|
}
|
|
else
|
|
{
|
|
Util.Debug.Trace("SearchMapFile",
|
|
"No mapping found for " + x.ToString() +
|
|
"," + y.ToString() + "\n");
|
|
}
|
|
|
|
return TargetUrl;
|
|
}
|
|
|
|
|
|
private void SkipLine()
|
|
{
|
|
while ((_index < _fileSize) &&
|
|
('\n' != _fileContents[_index]) )
|
|
_index++;
|
|
|
|
_index++;
|
|
}
|
|
|
|
|
|
private void SkipWhite()
|
|
{
|
|
while ( (_index < _fileSize) &&
|
|
( CharacterInfo.IsWhiteSpace(_fileContents[_index]) ||
|
|
(')' == _fileContents[_index]) ||
|
|
('(' == _fileContents[_index])))
|
|
_index++;
|
|
}
|
|
|
|
|
|
private void SkipWhiteExceptNewLine()
|
|
{
|
|
while ( (_index < _fileSize) &&
|
|
( CharacterInfo.IsWhiteSpace(_fileContents[_index]) ||
|
|
(')' == _fileContents[_index]) ||
|
|
('(' == _fileContents[_index])) &&
|
|
('\r' != _fileContents[_index]) &&
|
|
('\n' != _fileContents[_index]))
|
|
_index++;
|
|
}
|
|
|
|
|
|
private void SkipNonWhite()
|
|
{
|
|
while ( (_index < _fileSize) &&
|
|
(! CharacterInfo.IsWhiteSpace(_fileContents[_index])))
|
|
_index++;
|
|
}
|
|
|
|
|
|
int GetNumber()
|
|
{
|
|
int Value = Int32.MinValue;
|
|
char ch;
|
|
bool fNegative = false;
|
|
|
|
//
|
|
// Make sure we don't get into the URL
|
|
//
|
|
|
|
while (( _index < _fileSize ) &&
|
|
(!CharacterInfo.IsLetterOrDigit(ch=_fileContents[_index])) &&
|
|
( '-' != ch)&&( '/' != ch )&&( '\r' != ch)&&( '\n' != ch))
|
|
_index++;
|
|
|
|
//
|
|
// Read the number
|
|
//
|
|
if ((_index < _fileSize) &&
|
|
(_fileContents[_index] == '-'))
|
|
{
|
|
fNegative = true;
|
|
_index++;
|
|
}
|
|
|
|
while ((_index < _fileSize) &&
|
|
(CharacterInfo.IsDecimalDigit(ch = _fileContents[_index])))
|
|
{
|
|
if ( Int32.MinValue == Value)
|
|
Value = 0;
|
|
|
|
Value = Value*10 + (ch - '0');
|
|
_index++;
|
|
}
|
|
|
|
if (fNegative)
|
|
Value = -Value;
|
|
|
|
return Value;
|
|
}
|
|
|
|
|
|
private bool PointInRect(int x, int y)
|
|
{
|
|
bool fNCSA = false;
|
|
bool fFound = false;
|
|
|
|
char ch;
|
|
int x1, y1, x2, y2;
|
|
|
|
SkipNonWhite( );
|
|
_urlIndex = _index; // NCSA case
|
|
SkipWhiteExceptNewLine( );
|
|
|
|
ch = _fileContents[_index];
|
|
|
|
if ((!CharacterInfo.IsDecimalDigit(ch)) && (ch != '-') && (ch != '('))
|
|
{
|
|
//
|
|
// NCSA format. Skip the URL
|
|
//
|
|
|
|
fNCSA = true;
|
|
SkipNonWhite();
|
|
}
|
|
|
|
x1 = GetNumber( );
|
|
y1 = GetNumber( );
|
|
|
|
x2 = GetNumber( );
|
|
y2 = GetNumber( );
|
|
|
|
if ((x >= x1) && (x < x2) && (y >= y1) && (y < y2))
|
|
fFound = true;
|
|
|
|
if (!fNCSA)
|
|
{
|
|
_urlIndex = _index;
|
|
|
|
//
|
|
// Skip the URL
|
|
//
|
|
|
|
SkipWhiteExceptNewLine( );
|
|
SkipNonWhite( );
|
|
}
|
|
|
|
return fFound;
|
|
}
|
|
|
|
|
|
private bool PointInCircle(int x, int y)
|
|
{
|
|
bool fNCSA = false;
|
|
bool fFound = false;
|
|
|
|
double xCenter, yCenter, xEdge, yEdge;
|
|
double r1, r2;
|
|
char ch;
|
|
|
|
SkipNonWhite( );
|
|
_urlIndex = _index; // NCSA case
|
|
SkipWhiteExceptNewLine( );
|
|
|
|
ch = _fileContents[_index];
|
|
|
|
if ((!CharacterInfo.IsDecimalDigit(ch)) && (ch != '-') && (ch != '('))
|
|
{
|
|
//
|
|
// NCSA format. Skip the URL
|
|
//
|
|
|
|
fNCSA = true;
|
|
SkipNonWhite();
|
|
}
|
|
|
|
//
|
|
// Get the center and edge of the circle
|
|
//
|
|
|
|
xCenter = GetNumber( );
|
|
yCenter = GetNumber( );
|
|
|
|
xEdge = GetNumber( );
|
|
yEdge = GetNumber( );
|
|
|
|
//
|
|
// If there's a yEdge, then we have the NCSA format, otherwise
|
|
// we have the CERN format, which specifies a radius
|
|
//
|
|
|
|
if (Int32.MinValue != yEdge)
|
|
{
|
|
r1 = ((yCenter - yEdge) * (yCenter - yEdge)) +
|
|
((xCenter - xEdge) * (xCenter - xEdge));
|
|
|
|
r2 = ((yCenter - y) * (yCenter - y)) +
|
|
((xCenter - x) * (xCenter - x));
|
|
|
|
if ( r2 <= r1 )
|
|
fFound = true;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// CERN format, third param is the radius
|
|
//
|
|
|
|
if(xEdge >= 0)
|
|
{
|
|
double radius;
|
|
radius = xEdge;
|
|
|
|
if (( xCenter - x ) * ( xCenter - x) +
|
|
( yCenter - y ) * ( yCenter - y) <= ( radius * radius))
|
|
fFound = true;
|
|
}
|
|
// if invalid radius, just check if it is on center
|
|
else if ((xCenter == x) && (yCenter == y))
|
|
fFound = true;
|
|
}
|
|
|
|
if (!fNCSA)
|
|
{
|
|
_urlIndex = _index;
|
|
|
|
//
|
|
// Skip the URL
|
|
//
|
|
|
|
SkipWhiteExceptNewLine( );
|
|
SkipNonWhite( );
|
|
}
|
|
|
|
return fFound;
|
|
}
|
|
|
|
//
|
|
// Algorith used is from http://www.whisqu.se/per/docs/math27.htm
|
|
//
|
|
|
|
bool PointInPoly(int x, int y)
|
|
{
|
|
bool fNCSA = false;
|
|
bool fFound = false;
|
|
|
|
char ch;
|
|
ArrayList pgon = new ArrayList();
|
|
|
|
SkipNonWhite( );
|
|
_urlIndex = _index; // NCSA case
|
|
SkipWhiteExceptNewLine( );
|
|
|
|
ch = _fileContents[_index];
|
|
|
|
if ((!CharacterInfo.IsDecimalDigit(ch)) && (ch != '-') && (ch != '('))
|
|
{
|
|
//
|
|
// NCSA format. Skip the URL
|
|
//
|
|
|
|
fNCSA = true;
|
|
SkipNonWhite( );
|
|
}
|
|
|
|
//
|
|
// Build the array of points
|
|
//
|
|
|
|
while ((_index < _fileSize) &&
|
|
('\r' != _fileContents[_index]) &&
|
|
('\n' != _fileContents[_index]))
|
|
{
|
|
double[] point = new double[2];
|
|
point[X] = (double) GetNumber();
|
|
|
|
//
|
|
// Did we hit the end of the line (and go past the URL)?
|
|
//
|
|
|
|
if ( point[X] != Int32.MinValue )
|
|
{
|
|
point[Y] = (double) GetNumber( );
|
|
pgon.Add(point);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (pgon.Count > 1)
|
|
{
|
|
double tX, tY;
|
|
double prevX, prevY;
|
|
double currX, currY;
|
|
|
|
int i, crossings = 0;
|
|
|
|
tX = (double) x;
|
|
tY = (double) y;
|
|
|
|
double[] prevPoint = (double [])pgon[pgon.Count - 1];
|
|
prevX = prevPoint[X];
|
|
prevY = prevPoint[Y];
|
|
|
|
//
|
|
// Algorith used to find if the point is in the poly
|
|
// is from http://www.whisqu.se/per/docs/math27.htm
|
|
//
|
|
|
|
for ( i=0; i < pgon.Count; i++)
|
|
{
|
|
double interpY;
|
|
|
|
double[] currPoint = (double [])pgon[i];
|
|
currX = currPoint[X];
|
|
currY = currPoint[Y];
|
|
|
|
if (((prevX >= tX) && (currX < tX)) ||
|
|
((prevX < tX) && (currX >= tX)))
|
|
{
|
|
//
|
|
// Use linear interpolation to find the y coordinate of
|
|
// the line connecting (prevX, prevY) to (currX, currY)
|
|
// at the same x coordinate as the target point
|
|
//
|
|
|
|
interpY = prevY + ((currY - prevY)/(currX - prevX))* (tX - prevX);
|
|
|
|
if (interpY == tY)
|
|
{
|
|
fFound = true;
|
|
break;
|
|
}
|
|
else if (interpY > tY)
|
|
crossings++;
|
|
}
|
|
// To catch the left end of a line
|
|
else if (((prevX == tX) && (prevY == tY)) ||
|
|
((currX == tX) && (currY == tY)))
|
|
{
|
|
fFound = true;
|
|
break;
|
|
}
|
|
// To catch a vertical line
|
|
else if ((prevX == currX) && (prevX == tX))
|
|
if (((prevY >= tY) && ( currY <= tY)) ||
|
|
((prevY <= tY) && ( currY >= tY)))
|
|
{
|
|
fFound = true;
|
|
break;
|
|
}
|
|
|
|
prevX = currX;
|
|
prevY = currY;
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
//
|
|
// If # crossings is odd => In polygon
|
|
//
|
|
|
|
fFound = ( 0 != (crossings & 0x01));
|
|
}
|
|
}
|
|
|
|
if (!fNCSA)
|
|
{
|
|
|
|
_urlIndex = _index;
|
|
|
|
//
|
|
// Skip the URL
|
|
//
|
|
|
|
SkipWhiteExceptNewLine( );
|
|
SkipNonWhite( );
|
|
}
|
|
|
|
return fFound;
|
|
}
|
|
|
|
|
|
private double PointInPoint(int x, int y)
|
|
{
|
|
double x1, y1;
|
|
|
|
SkipNonWhite( );
|
|
|
|
_urlIndex = _index; // NCSA case
|
|
|
|
SkipWhiteExceptNewLine( );
|
|
SkipNonWhite( );
|
|
|
|
x1 = (double)GetNumber( );
|
|
y1 = (double)GetNumber( );
|
|
|
|
return ((x1-x)*(x1-x)) + ((y1-y)*(y1-y));
|
|
}
|
|
|
|
|
|
private int GetDefaultUrl()
|
|
{
|
|
//
|
|
// Skip "default" (don't skip white space)
|
|
//
|
|
|
|
SkipNonWhite( );
|
|
_urlIndex = _index;
|
|
|
|
//
|
|
// Skip URL
|
|
//
|
|
|
|
SkipWhiteExceptNewLine( );
|
|
SkipNonWhite( );
|
|
|
|
return _urlIndex;
|
|
}
|
|
|
|
|
|
private int Compare(String a, char[] b, int boffset, int length)
|
|
{
|
|
String tmp = new String(b, boffset, length);
|
|
|
|
return String.Compare( a, 0, tmp, 0, length, true);
|
|
}
|
|
|
|
public bool IsReusable()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
}
|
|
}
|