/*++ Copyright (c) 2000 Microsoft Corporation Module Name : map_handler.cxx Abstract: Handle Map Files requests Author: Anil Ruia (AnilR) 9-Mar-2000 Environment: Win32 - User Mode Project: ULW3.DLL --*/ #include "precomp.hxx" #include "staticfile.hxx" #define MAXVERTS 160 const int MIN_INTEGER = 0x80000001; void SkipLine(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex); void SkipWhiteExceptNewLine(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex); void SkipWhite(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex); void SkipNonWhite(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex); int GetNumber(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex); BOOL PointInRect(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex); BOOL PointInCircle(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex); BOOL PointInPoly(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex); double PointInPoint(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex); DWORD GetDefaultUrl(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex); HRESULT W3_STATIC_FILE_HANDLER::MapFileDoWork( W3_CONTEXT *pW3Context, W3_FILE_INFO *pOpenFile, BOOL *pfHandled) { DBG_ASSERT(pW3Context != NULL); DBG_ASSERT(pOpenFile != NULL); DBG_ASSERT(pfHandled != NULL); STACK_STRA(strTargetUrl, MAX_PATH); STACK_STRU(strQueryString, MAX_PATH); LPSTR pszFileContents = NULL; BOOL fFileContentsAllocated = FALSE; int x = 0; int y = 0; HRESULT hr = S_OK; W3_REQUEST *pRequest = pW3Context->QueryRequest(); DBG_ASSERT(pRequest != NULL); *pfHandled = FALSE; DWORD cbFileSize; ULARGE_INTEGER liFileSize; pOpenFile->QuerySize(&liFileSize); cbFileSize = liFileSize.LowPart; if (pOpenFile->QueryFileBuffer() != NULL) { pszFileContents = (LPSTR)pOpenFile->QueryFileBuffer(); } else { pszFileContents = new CHAR[cbFileSize]; if (pszFileContents == NULL) { hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); goto Finished; } fFileContentsAllocated = TRUE; DWORD cbRead; OVERLAPPED ovl; ZeroMemory(&ovl, sizeof ovl); if (!ReadFile(pOpenFile->QueryFileHandle(), pszFileContents, cbFileSize, &cbRead, &ovl)) { hr = HRESULT_FROM_WIN32(GetLastError()); switch (hr) { case HRESULT_FROM_WIN32(ERROR_IO_PENDING): if (!GetOverlappedResult(pOpenFile->QueryFileHandle(), &ovl, &cbRead, TRUE)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Finished; } break; default: goto Finished; } } } if (FAILED(hr = pW3Context->QueryRequest()->GetQueryString(&strQueryString))) { goto Finished; } strQueryString.Unescape(); swscanf(strQueryString.QueryStr(), L"%d, %d", &x, &y); if (FAILED(hr = SearchMapFile(pszFileContents, cbFileSize, x, y, &strTargetUrl))) { goto Finished; } if (strTargetUrl.QueryCCH() == 0) { // // No entry found // LPCSTR pszReferer; if ((pszReferer = pRequest->GetHeader(HttpHeaderReferer)) != NULL) { // // Redirect back to referrer // strTargetUrl.Copy(pszReferer); } else { *pfHandled = FALSE; goto Finished; } } *pfHandled = TRUE; hr = pW3Context->SetupHttpRedirect(strTargetUrl, FALSE, HttpStatusRedirect); Finished: if (fFileContentsAllocated) { delete [] pszFileContents; } return hr; } HRESULT W3_STATIC_FILE_HANDLER::SearchMapFile( IN LPCSTR pszFileContents, IN const DWORD cbFileSize, IN const int x, IN const int y, OUT STRA *pstrTarget) { DWORD fileIndex = 0; DWORD urlIndex = 0; BOOL fFound = FALSE; double MinDistanceFromPoint = 1e64; DWORD PointUrlIndex = 0; DWORD DefaultUrlIndex = 0; while ((fileIndex < cbFileSize) && !fFound) { switch (pszFileContents[fileIndex]) { case '#': // // Comment, skip the line // break; case 'r': case 'R': // // Rectangle // if ((fileIndex < (cbFileSize - 4)) && !_strnicmp("rect", pszFileContents + fileIndex, 4)) { fileIndex += 4; fFound = PointInRect(pszFileContents, cbFileSize, fileIndex, x, y, urlIndex); } break; case 'c': case 'C': // // Circle // if ((fileIndex < (cbFileSize - 4)) && !_strnicmp("circ", pszFileContents + fileIndex, 4)) { fileIndex += 4; fFound = PointInCircle(pszFileContents, cbFileSize, fileIndex, x, y, urlIndex); } break; case 'p': case 'P': // // Polygon or point // if ((fileIndex < (cbFileSize - 4)) && !_strnicmp("poly", pszFileContents + fileIndex, 4)) { fileIndex += 4; fFound = PointInPoly(pszFileContents, cbFileSize, fileIndex, x, y, urlIndex); } else if ((fileIndex < (cbFileSize - 5)) && !_strnicmp("point", pszFileContents + fileIndex, 5)) { fileIndex += 5; double distance = PointInPoint(pszFileContents, cbFileSize, fileIndex, x, y, urlIndex); if (distance < MinDistanceFromPoint) { MinDistanceFromPoint = distance; PointUrlIndex = urlIndex; } } break; case 'd': case 'D': // // default URL // if ((fileIndex < (cbFileSize - 3)) && !_strnicmp("def", pszFileContents + fileIndex, 3)) { fileIndex += 3; DefaultUrlIndex = GetDefaultUrl(pszFileContents, cbFileSize, fileIndex); } break; } // switch if (!fFound) SkipLine(pszFileContents, cbFileSize, fileIndex); } // while // // If we didn't find a mapping and a point or a default was specified, // use that URL // if (!fFound) { if (PointUrlIndex != 0) { urlIndex = PointUrlIndex; fFound = TRUE; } else if (DefaultUrlIndex != 0) { urlIndex = DefaultUrlIndex; fFound = TRUE; } } if (fFound) { // // make urlIndex point to the start of the URL // SkipWhiteExceptNewLine(pszFileContents, cbFileSize, urlIndex); // // Determine the length of the URL and copy it out // DWORD endOfUrlIndex = urlIndex; SkipNonWhite(pszFileContents, cbFileSize, endOfUrlIndex); HRESULT hr; if (FAILED(hr = pstrTarget->Copy(pszFileContents + urlIndex, endOfUrlIndex - urlIndex))) { return hr; } // // BUGBUG - Escape the URL // } else { DBGPRINTF((DBG_CONTEXT, "No mapping found for %d, %d\n", x, y)); } return S_OK; } void SkipLine(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex) { while ((fileIndex < cbFileSize) && (pszFileContents[fileIndex] != '\n')) fileIndex++; fileIndex++; } void SkipWhiteExceptNewLine(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex) { while ((fileIndex < cbFileSize) && ((pszFileContents[fileIndex] == ' ') || (pszFileContents[fileIndex] == '\t') || (pszFileContents[fileIndex] == '(') || (pszFileContents[fileIndex] == ')'))) { fileIndex++; } } void SkipWhite(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex) { while ((fileIndex < cbFileSize) && ((pszFileContents[fileIndex] == ' ') || (pszFileContents[fileIndex] == '\t') || (pszFileContents[fileIndex] == '\r') || (pszFileContents[fileIndex] == '\n') || (pszFileContents[fileIndex] == '(') || (pszFileContents[fileIndex] == ')'))) { fileIndex++; } } void SkipNonWhite(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex) { while ((fileIndex < cbFileSize) && (pszFileContents[fileIndex] != ' ') && (pszFileContents[fileIndex] != '\t') && (pszFileContents[fileIndex] != '\r') && (pszFileContents[fileIndex] != '\n')) { fileIndex++; } } int GetNumber(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex) { int Value = MIN_INTEGER; char ch; bool fNegative = false; // // Make sure we don't get into the URL // while ((fileIndex < cbFileSize) && !isalnum(ch = pszFileContents[fileIndex]) && (ch != '-') && (ch != '/') && (ch != '\r') && (ch != '\n')) { fileIndex++; } // // Read the number // if ((fileIndex < cbFileSize) && (pszFileContents[fileIndex] == '-')) { fNegative = true; fileIndex++; } while ((fileIndex < cbFileSize) && isdigit(ch = pszFileContents[fileIndex])) { if (Value == MIN_INTEGER) Value = 0; Value = Value*10 + (ch - '0'); fileIndex++; } if (fNegative) Value = -Value; return Value; } BOOL PointInRect(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex) { BOOL fNCSA = FALSE; BOOL fFound = FALSE; SkipNonWhite(pszFileContents, cbFileSize, fileIndex); urlIndex = fileIndex; // NCSA case SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); char ch = pszFileContents[fileIndex]; if (((ch < '0') || (ch > '9')) && (ch != '-') && (ch != '(')) { // // NCSA format. Skip the URL // fNCSA = true; SkipNonWhite(pszFileContents, cbFileSize, fileIndex); } int x1 = GetNumber(pszFileContents, cbFileSize, fileIndex); int y1 = GetNumber(pszFileContents, cbFileSize, fileIndex); int x2 = GetNumber(pszFileContents, cbFileSize, fileIndex); int y2 = GetNumber(pszFileContents, cbFileSize, fileIndex); if ((x >= x1) && (x < x2) && (y >= y1) && (y < y2)) fFound = true; if (!fNCSA) { urlIndex = fileIndex; // // Skip the URL // SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); SkipNonWhite(pszFileContents, cbFileSize, fileIndex); } return fFound; } BOOL PointInCircle(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex) { BOOL fNCSA = FALSE; BOOL fFound = FALSE; double r1, r2; SkipNonWhite(pszFileContents, cbFileSize, fileIndex); urlIndex = fileIndex; // NCSA case SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); char ch = pszFileContents[fileIndex]; if (!isdigit(ch) && (ch != '-') && (ch != '(')) { // // NCSA format. Skip the URL // fNCSA = true; SkipNonWhite(pszFileContents, cbFileSize, fileIndex); } // // Get the center and edge of the circle // double xCenter = GetNumber(pszFileContents, cbFileSize, fileIndex); double yCenter = GetNumber(pszFileContents, cbFileSize, fileIndex); double xEdge = GetNumber(pszFileContents, cbFileSize, fileIndex); double yEdge = GetNumber(pszFileContents, cbFileSize, fileIndex); // // If we have the NCSA format, (xEdge, yEdge) is a point on the // circumference. Otherwise xEdge specifies the radius // if (yEdge != (double)MIN_INTEGER) { r1 = (yCenter - yEdge) * (yCenter - yEdge) + (xCenter - xEdge) * (xCenter - xEdge); r2 = (yCenter - y) * (yCenter - y) + (xCenter - x) * (xCenter - x); if ( r2 <= r1 ) fFound = true; } // // CERN format, third param is the radius // else 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 = fileIndex; // // Skip the URL // SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); SkipNonWhite(pszFileContents, cbFileSize, fileIndex); } return fFound; } const int X = 0; const int Y = 1; BOOL PointInPoly(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex) { // // Algorithm used is from http://www.whisqu.se/per/docs/math27.htm // BOOL fNCSA = FALSE; BOOL fFound = FALSE; SkipNonWhite(pszFileContents, cbFileSize, fileIndex); urlIndex = fileIndex; // NCSA case SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); char ch = pszFileContents[fileIndex]; if (!isdigit(ch) && (ch != '-') && (ch != '(')) { // // NCSA format. Skip the URL // fNCSA = TRUE; SkipNonWhite(pszFileContents, cbFileSize, fileIndex); } // // Build the array of points // double polygon[MAXVERTS][2]; int count = 0; while ((fileIndex < cbFileSize) && (pszFileContents[fileIndex] != '\r') && (pszFileContents[fileIndex] != '\n')) { int polyX = GetNumber(pszFileContents, cbFileSize, fileIndex); // // Did we hit the end of the line (and go past the URL)? // if ( polyX != MIN_INTEGER) { polygon[count][X] = polyX; polygon[count][Y] = GetNumber(pszFileContents, cbFileSize, fileIndex); count++; if (count >= MAXVERTS) return FALSE; } else break; } if (count > 1) { double tX = x; double tY = y; double prevX = polygon[count - 1][X]; double prevY = polygon[count - 1][Y]; double currX, currY; int crossings = 0; for (int i=0; i < count; i++) { double interpY; currX = polygon[i][X]; currY = polygon[i][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 = crossings & 0x1; } } if (!fNCSA) { urlIndex = fileIndex; // // Skip the URL // SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); SkipNonWhite(pszFileContents, cbFileSize, fileIndex); } return fFound; } double PointInPoint(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex, const int x, const int y, DWORD &urlIndex) { SkipNonWhite(pszFileContents, cbFileSize, fileIndex); urlIndex = fileIndex; // NCSA case SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); SkipNonWhite(pszFileContents, cbFileSize, fileIndex); double x1 = GetNumber(pszFileContents, cbFileSize, fileIndex); double y1 = GetNumber(pszFileContents, cbFileSize, fileIndex); return ((x1-x)*(x1-x)) + ((y1-y)*(y1-y)); } DWORD GetDefaultUrl(LPCSTR pszFileContents, const DWORD cbFileSize, DWORD &fileIndex) { // // Skip "default" (don't skip white space) // SkipNonWhite(pszFileContents, cbFileSize, fileIndex); DWORD defUrlIndex = fileIndex; // // Skip URL // SkipWhiteExceptNewLine(pszFileContents, cbFileSize, fileIndex); SkipNonWhite(pszFileContents, cbFileSize, fileIndex); return defUrlIndex; }