/* * H T M L M A P . C P P * * HTML .MAP file processing * * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved */ #include "_davprs.h" #include // .MAP file parsing --------------------------------------------------------- // // This code has been stolen from IIS and rewritten to work within the // DAV/Caligula sources. The original code can be found in the IIS slm // project at \\kernel\razzle3\slm\iis\svcs\w3\server\doget.cxx. // #define SQR(x) ((x) * (x)) #define MAXVERTS 160 #define X 0 #define Y 1 inline bool IsWhiteA (CHAR ch) { return ((ch) == '\t' || (ch) == ' ' || (ch) == '\r'); } inline CHAR * SkipNonWhite( CHAR * pch ) { while (*pch && !IsWhiteA(*pch)) pch++; return pch; } inline CHAR * SkipWhite( CHAR * pch ) { while (IsWhiteA(*pch) || (*pch == ')') || (*pch == '(')) pch++; return pch; } int GetNumber( CHAR ** ppch ) { CHAR * pch = *ppch; INT n; // Make sure we don't get into the URL // while ( *pch && !isdigit( *pch ) && !isalpha( *pch ) && *pch != '/' && *pch != '\r' && *pch != '\n' ) { pch++; } if ( !isdigit( *pch ) ) return -1; n = atoi( pch ); while ( isdigit( *pch )) pch++; *ppch = pch; return n; } int pointinpoly(int point_x, int point_y, double pgon[MAXVERTS][2]) { int i, numverts, inside_flag, xflag0; int crossings; double *p, *stop; double tx, ty, y; for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++) ; numverts = i; crossings = 0; tx = (double) point_x; ty = (double) point_y; y = pgon[numverts - 1][Y]; p = (double *) pgon + 1; if ((y >= ty) != (*p >= ty)) { if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) { if (xflag0) crossings++; } else { crossings += (pgon[numverts - 1][X] - (y - ty) * (*(double *) pgon - pgon[numverts - 1][X]) / (*p - y)) >= tx; } } stop = pgon[numverts]; for (y = *p, p += 2; p < stop; y = *p, p += 2) { if (y >= ty) { while ((p < stop) && (*p >= ty)) p += 2; if (p >= stop) break; if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { if (xflag0) crossings++; } else { crossings += (*(p - 3) - (*(p - 2) - ty) * (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; } } else { while ((p < stop) && (*p < ty)) p += 2; if (p >= stop) break; if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { if (xflag0) crossings++; } else { crossings += (*(p - 3) - (*(p - 2) - ty) * (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; } } } inside_flag = crossings & 0x01; return (inside_flag); } BOOL FSearchMapFile (LPCSTR pszMap, INT x, INT y, BOOL * pfRedirect, LPSTR pszRedirect, UINT cchBuf) { BOOL fRet = FALSE; CHAR * pch; CHAR * pchDefault = NULL; CHAR * pchPoint = NULL; CHAR * pchStart; UINT cchUrl; UINT dis; UINT bdis = static_cast(-1); BOOL fComment = FALSE; BOOL fIsNCSA = FALSE; LPSTR pURL; // valid only if fIsNCSA is TRUE // We should now be ready to parse the map. Here is where the // IIS code begins. // fRet = TRUE; // Loop through the contents of the buffer and see what we've got // for (pch = const_cast(pszMap); *pch; ) { fIsNCSA = FALSE; // note: _tolower doesn't check case (tolower does) // switch( ( *pch >= 'A' && *pch <= 'Z' ) ? _tolower( *pch ) : *pch ) { case '#': fComment = TRUE; break; case '\r': case '\n': fComment = FALSE; break; // Rectangle // case 'r': case 'o': // In the IIS code, "oval" and "rect" are treated the // same. The code is commented with a BUGBUG comment. // if( !fComment && ( !_strnicmp( "rect", pch, 4) // BUGBUG handles oval as a rect, as they are using // the same specification format. Should do better. || !_strnicmp( "oval", pch, 4 )) ) { INT x1, y1, x2, y2; pch = SkipNonWhite( pch ); pURL = pch; pch = SkipWhite( pch ); if( !isdigit(*pch) && *pch!='(' ) { fIsNCSA = TRUE; pch = SkipNonWhite( pch ); } x1 = GetNumber( &pch ); y1 = GetNumber( &pch ); x2 = GetNumber( &pch ); y2 = GetNumber( &pch ); if ( x >= x1 && x < x2 && y >= y1 && y < y2 ) { if ( fIsNCSA ) pch = pURL; goto Found; } // Skip the URL // if( !fIsNCSA ) { pch = SkipWhite( pch ); pch = SkipNonWhite( pch ); } continue; } break; // Circle // case 'c': if ( !fComment && !_strnicmp( "circ", pch, 4 )) { INT xCenter, yCenter, xEdge, yEdge; INT r1, r2; pch = SkipNonWhite( pch ); pURL = pch; pch = SkipWhite( pch ); if ( !isdigit(*pch) && *pch!='(' ) { fIsNCSA = TRUE; pch = SkipNonWhite( pch ); } // Get the center and edge of the circle // xCenter = GetNumber( &pch ); yCenter = GetNumber( &pch ); xEdge = GetNumber( &pch ); yEdge = GetNumber( &pch ); // If there's a yEdge, then we have the NCSA format, otherwise // we have the CERN format, which specifies a radius // if ( yEdge != -1 ) { r1 = ((yCenter - yEdge) * (yCenter - yEdge)) + ((xCenter - xEdge) * (xCenter - xEdge)); r2 = ((yCenter - y) * (yCenter - y)) + ((xCenter - x) * (xCenter - x)); if ( r2 <= r1 ) { if ( fIsNCSA ) pch = pURL; goto Found; } } else { INT radius; // CERN format, third param is the radius // radius = xEdge; if ( SQR( xCenter - x ) + SQR( yCenter - y ) <= SQR( radius )) { if ( fIsNCSA ) pch = pURL; goto Found; } } // Skip the URL // if ( !fIsNCSA ) { pch = SkipWhite( pch ); pch = SkipNonWhite( pch ); } continue; } break; // Polygon // case 'p': if ( !fComment && !_strnicmp( "poly", pch, 4 )) { double pgon[MAXVERTS][2]; DWORD i = 0; BOOL fOverflow = FALSE; pch = SkipNonWhite( pch ); pURL = pch; pch = SkipWhite( pch ); if ( !isdigit(*pch) && *pch!='(' ) { fIsNCSA = TRUE; pch = SkipNonWhite( pch ); } // Build the array of points // while ( *pch && *pch != '\r' && *pch != '\n' ) { pgon[i][0] = GetNumber( &pch ); // // Did we hit the end of the line (and go past the URL)? // if ( pgon[i][0] != -1 ) { pgon[i][1] = GetNumber( &pch ); } else { break; } if ( i < MAXVERTS-1 ) { i++; } else { fOverflow = TRUE; } } pgon[i][X] = -1; if ( !fOverflow && pointinpoly( x, y, pgon )) { if ( fIsNCSA ) pch = pURL; goto Found; } // Skip the URL // if ( !fIsNCSA ) { pch = SkipWhite( pch ); pch = SkipNonWhite( pch ); } continue; } else if ( !fComment && !_strnicmp( "point", pch, 5 )) { INT x1,y1; pch = SkipNonWhite( pch ); pURL = pch; pch = SkipWhite( pch ); pch = SkipNonWhite( pch ); x1 = GetNumber( &pch ); y1 = GetNumber( &pch ); x1 -= x; y1 -= y; dis = x1*x1 + y1*y1; if ( dis < bdis ) { pchPoint = pURL; bdis = dis; } } break; // Default URL // case 'd': if ( !fComment && !_strnicmp( "def", pch, 3 ) ) { // // Skip "default" (don't skip white space) // pch = SkipNonWhite( pch ); pchDefault = pch; // // Skip URL // pch = SkipWhite( pch ); pch = SkipNonWhite( pch ); continue; } break; } pch++; pch = SkipWhite( pch ); } // If we didn't find a mapping and a default was specified, use // the default URL // if ( pchPoint ) { pch = pchPoint; goto Found; } if ( pchDefault ) { pch = pchDefault; goto Found; } DebugTrace ("Dav: no mapping found for (%d, %d)\n", x, y); goto Exit; Found: // pch should point to the white space immediately before the URL // pch = SkipWhite( pch ); pchStart = pch; pch = SkipNonWhite( pch ); // Determine the length of the URL and copy it out // cchUrl = static_cast(pch - pchStart); if ( cchUrl >= cchBuf ) return FALSE; CopyMemory (pszRedirect, pchStart, cchUrl); *(pszRedirect + cchUrl) = 0; *pfRedirect = TRUE; DebugTrace ("Dav: mapping for (%d, %d) is %hs\n", x, y, pszRedirect); Exit: return fRet; } BOOL FIsMapProcessed ( LPCSTR lpszQueryString, LPCSTR lpszUrlPrefix, LPCSTR lpszServerName, LPCSTR pszMap, BOOL * pfRedirect, LPSTR pszRedirect, UINT cchBuf) { INT x = 0; INT y = 0; LPCSTR pch = lpszQueryString; // Ensure the *pfRedirect is initialized // Assert( pfRedirect ); *pfRedirect = FALSE; // If there is no query string, I don't think we want to process // the file as if it were a .map request. // if ( pch == NULL ) return TRUE; // Get the x and y cooridinates of the mouse click on the image // x = strtoul( pch, NULL, 10 ); // Move past x and any intervening delimiters // while ( isdigit( *pch )) pch++; while ( *pch && !isdigit( *pch )) pch++; y = strtoul( pch, NULL, 10 ); // Search the map file // if ( !FSearchMapFile( pszMap, x, y, pfRedirect, pszRedirect, cchBuf)) { DebugTrace ("Dav: FSearchMapFile() failed with %ld\n", GetLastError()); return FALSE; } // If no redirected URL was passed back, then we are done. // if ( !*pfRedirect ) { // Returning true does not indicate success, it really // just means that there were no processing errors // goto ret; } // 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 ( *pszRedirect == '/' ) { CHAR rgch[MAX_PATH]; UINT cch; UINT cchUri; if ( strlen(lpszUrlPrefix) + strlen(lpszServerName) >= MAX_PATH) return FALSE; // Build up the full qualification to the url // strcpy (rgch, lpszUrlPrefix); strcat (rgch, lpszServerName); // See how much we need to shif the URL by // cch = static_cast(strlen (rgch)); cchUri = static_cast(strlen (pszRedirect)); // If they haven't passed us enough buffer to copy // the redirect url, fail. Add one to the counts for the // terminating NULL character // if (cchBuf < (cchUri + cch + 1)) return FALSE; MoveMemory (pszRedirect + cch, pszRedirect, cchUri + 1); CopyMemory (pszRedirect, rgch, cch); } ret: return TRUE; }