Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

584 lines
11 KiB

  1. /*
  2. * H T M L M A P . C P P
  3. *
  4. * HTML .MAP file processing
  5. *
  6. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  7. */
  8. #include "_davprs.h"
  9. #include <htmlmap.h>
  10. // .MAP file parsing ---------------------------------------------------------
  11. //
  12. // This code has been stolen from IIS and rewritten to work within the
  13. // DAV/Caligula sources. The original code can be found in the IIS slm
  14. // project at \\kernel\razzle3\slm\iis\svcs\w3\server\doget.cxx.
  15. //
  16. #define SQR(x) ((x) * (x))
  17. #define MAXVERTS 160
  18. #define X 0
  19. #define Y 1
  20. inline bool IsWhiteA (CHAR ch)
  21. {
  22. return ((ch) == '\t' || (ch) == ' ' || (ch) == '\r');
  23. }
  24. inline CHAR * SkipNonWhite( CHAR * pch )
  25. {
  26. while (*pch && !IsWhiteA(*pch))
  27. pch++;
  28. return pch;
  29. }
  30. inline CHAR * SkipWhite( CHAR * pch )
  31. {
  32. while (IsWhiteA(*pch) || (*pch == ')') || (*pch == '('))
  33. pch++;
  34. return pch;
  35. }
  36. int GetNumber( CHAR ** ppch )
  37. {
  38. CHAR * pch = *ppch;
  39. INT n;
  40. // Make sure we don't get into the URL
  41. //
  42. while ( *pch &&
  43. !isdigit( *pch ) &&
  44. !isalpha( *pch ) &&
  45. *pch != '/' &&
  46. *pch != '\r' &&
  47. *pch != '\n' )
  48. {
  49. pch++;
  50. }
  51. if ( !isdigit( *pch ) )
  52. return -1;
  53. n = atoi( pch );
  54. while ( isdigit( *pch ))
  55. pch++;
  56. *ppch = pch;
  57. return n;
  58. }
  59. int pointinpoly(int point_x, int point_y, double pgon[MAXVERTS][2])
  60. {
  61. int i, numverts, inside_flag, xflag0;
  62. int crossings;
  63. double *p, *stop;
  64. double tx, ty, y;
  65. for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++)
  66. ;
  67. numverts = i;
  68. crossings = 0;
  69. tx = (double) point_x;
  70. ty = (double) point_y;
  71. y = pgon[numverts - 1][Y];
  72. p = (double *) pgon + 1;
  73. if ((y >= ty) != (*p >= ty))
  74. {
  75. if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx))
  76. {
  77. if (xflag0)
  78. crossings++;
  79. }
  80. else
  81. {
  82. crossings += (pgon[numverts - 1][X] - (y - ty) *
  83. (*(double *) pgon - pgon[numverts - 1][X]) /
  84. (*p - y)) >= tx;
  85. }
  86. }
  87. stop = pgon[numverts];
  88. for (y = *p, p += 2; p < stop; y = *p, p += 2)
  89. {
  90. if (y >= ty)
  91. {
  92. while ((p < stop) && (*p >= ty))
  93. p += 2;
  94. if (p >= stop)
  95. break;
  96. if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx))
  97. {
  98. if (xflag0)
  99. crossings++;
  100. }
  101. else
  102. {
  103. crossings += (*(p - 3) - (*(p - 2) - ty) *
  104. (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
  105. }
  106. }
  107. else
  108. {
  109. while ((p < stop) && (*p < ty))
  110. p += 2;
  111. if (p >= stop)
  112. break;
  113. if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx))
  114. {
  115. if (xflag0)
  116. crossings++;
  117. }
  118. else
  119. {
  120. crossings += (*(p - 3) - (*(p - 2) - ty) *
  121. (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
  122. }
  123. }
  124. }
  125. inside_flag = crossings & 0x01;
  126. return (inside_flag);
  127. }
  128. BOOL
  129. FSearchMapFile (LPCSTR pszMap,
  130. INT x,
  131. INT y,
  132. BOOL * pfRedirect,
  133. LPSTR pszRedirect,
  134. UINT cchBuf)
  135. {
  136. BOOL fRet = FALSE;
  137. CHAR * pch;
  138. CHAR * pchDefault = NULL;
  139. CHAR * pchPoint = NULL;
  140. CHAR * pchStart;
  141. UINT cchUrl;
  142. UINT dis;
  143. UINT bdis = static_cast<UINT>(-1);
  144. BOOL fComment = FALSE;
  145. BOOL fIsNCSA = FALSE;
  146. LPSTR pURL; // valid only if fIsNCSA is TRUE
  147. // We should now be ready to parse the map. Here is where the
  148. // IIS code begins.
  149. //
  150. fRet = TRUE;
  151. // Loop through the contents of the buffer and see what we've got
  152. //
  153. for (pch = const_cast<CHAR *>(pszMap); *pch; )
  154. {
  155. fIsNCSA = FALSE;
  156. // note: _tolower doesn't check case (tolower does)
  157. //
  158. switch( ( *pch >= 'A' && *pch <= 'Z' ) ? _tolower( *pch ) : *pch )
  159. {
  160. case '#':
  161. fComment = TRUE;
  162. break;
  163. case '\r':
  164. case '\n':
  165. fComment = FALSE;
  166. break;
  167. // Rectangle
  168. //
  169. case 'r':
  170. case 'o':
  171. // In the IIS code, "oval" and "rect" are treated the
  172. // same. The code is commented with a BUGBUG comment.
  173. //
  174. if( !fComment &&
  175. ( !_strnicmp( "rect", pch, 4)
  176. // BUGBUG handles oval as a rect, as they are using
  177. // the same specification format. Should do better.
  178. || !_strnicmp( "oval", pch, 4 )) )
  179. {
  180. INT x1, y1, x2, y2;
  181. pch = SkipNonWhite( pch );
  182. pURL = pch;
  183. pch = SkipWhite( pch );
  184. if( !isdigit(*pch) && *pch!='(' )
  185. {
  186. fIsNCSA = TRUE;
  187. pch = SkipNonWhite( pch );
  188. }
  189. x1 = GetNumber( &pch );
  190. y1 = GetNumber( &pch );
  191. x2 = GetNumber( &pch );
  192. y2 = GetNumber( &pch );
  193. if ( x >= x1 && x < x2 &&
  194. y >= y1 && y < y2 )
  195. {
  196. if ( fIsNCSA )
  197. pch = pURL;
  198. goto Found;
  199. }
  200. // Skip the URL
  201. //
  202. if( !fIsNCSA )
  203. {
  204. pch = SkipWhite( pch );
  205. pch = SkipNonWhite( pch );
  206. }
  207. continue;
  208. }
  209. break;
  210. // Circle
  211. //
  212. case 'c':
  213. if ( !fComment &&
  214. !_strnicmp( "circ", pch, 4 ))
  215. {
  216. INT xCenter, yCenter, xEdge, yEdge;
  217. INT r1, r2;
  218. pch = SkipNonWhite( pch );
  219. pURL = pch;
  220. pch = SkipWhite( pch );
  221. if ( !isdigit(*pch) && *pch!='(' )
  222. {
  223. fIsNCSA = TRUE;
  224. pch = SkipNonWhite( pch );
  225. }
  226. // Get the center and edge of the circle
  227. //
  228. xCenter = GetNumber( &pch );
  229. yCenter = GetNumber( &pch );
  230. xEdge = GetNumber( &pch );
  231. yEdge = GetNumber( &pch );
  232. // If there's a yEdge, then we have the NCSA format, otherwise
  233. // we have the CERN format, which specifies a radius
  234. //
  235. if ( yEdge != -1 )
  236. {
  237. r1 = ((yCenter - yEdge) * (yCenter - yEdge)) +
  238. ((xCenter - xEdge) * (xCenter - xEdge));
  239. r2 = ((yCenter - y) * (yCenter - y)) +
  240. ((xCenter - x) * (xCenter - x));
  241. if ( r2 <= r1 )
  242. {
  243. if ( fIsNCSA )
  244. pch = pURL;
  245. goto Found;
  246. }
  247. }
  248. else
  249. {
  250. INT radius;
  251. // CERN format, third param is the radius
  252. //
  253. radius = xEdge;
  254. if ( SQR( xCenter - x ) + SQR( yCenter - y ) <=
  255. SQR( radius ))
  256. {
  257. if ( fIsNCSA )
  258. pch = pURL;
  259. goto Found;
  260. }
  261. }
  262. // Skip the URL
  263. //
  264. if ( !fIsNCSA )
  265. {
  266. pch = SkipWhite( pch );
  267. pch = SkipNonWhite( pch );
  268. }
  269. continue;
  270. }
  271. break;
  272. // Polygon
  273. //
  274. case 'p':
  275. if ( !fComment &&
  276. !_strnicmp( "poly", pch, 4 ))
  277. {
  278. double pgon[MAXVERTS][2];
  279. DWORD i = 0;
  280. BOOL fOverflow = FALSE;
  281. pch = SkipNonWhite( pch );
  282. pURL = pch;
  283. pch = SkipWhite( pch );
  284. if ( !isdigit(*pch) && *pch!='(' )
  285. {
  286. fIsNCSA = TRUE;
  287. pch = SkipNonWhite( pch );
  288. }
  289. // Build the array of points
  290. //
  291. while ( *pch && *pch != '\r' && *pch != '\n' )
  292. {
  293. pgon[i][0] = GetNumber( &pch );
  294. //
  295. // Did we hit the end of the line (and go past the URL)?
  296. //
  297. if ( pgon[i][0] != -1 )
  298. {
  299. pgon[i][1] = GetNumber( &pch );
  300. }
  301. else
  302. {
  303. break;
  304. }
  305. if ( i < MAXVERTS-1 )
  306. {
  307. i++;
  308. }
  309. else
  310. {
  311. fOverflow = TRUE;
  312. }
  313. }
  314. pgon[i][X] = -1;
  315. if ( !fOverflow && pointinpoly( x, y, pgon ))
  316. {
  317. if ( fIsNCSA )
  318. pch = pURL;
  319. goto Found;
  320. }
  321. // Skip the URL
  322. //
  323. if ( !fIsNCSA )
  324. {
  325. pch = SkipWhite( pch );
  326. pch = SkipNonWhite( pch );
  327. }
  328. continue;
  329. }
  330. else if ( !fComment &&
  331. !_strnicmp( "point", pch, 5 ))
  332. {
  333. INT x1,y1;
  334. pch = SkipNonWhite( pch );
  335. pURL = pch;
  336. pch = SkipWhite( pch );
  337. pch = SkipNonWhite( pch );
  338. x1 = GetNumber( &pch );
  339. y1 = GetNumber( &pch );
  340. x1 -= x;
  341. y1 -= y;
  342. dis = x1*x1 + y1*y1;
  343. if ( dis < bdis )
  344. {
  345. pchPoint = pURL;
  346. bdis = dis;
  347. }
  348. }
  349. break;
  350. // Default URL
  351. //
  352. case 'd':
  353. if ( !fComment &&
  354. !_strnicmp( "def", pch, 3 ) )
  355. {
  356. //
  357. // Skip "default" (don't skip white space)
  358. //
  359. pch = SkipNonWhite( pch );
  360. pchDefault = pch;
  361. //
  362. // Skip URL
  363. //
  364. pch = SkipWhite( pch );
  365. pch = SkipNonWhite( pch );
  366. continue;
  367. }
  368. break;
  369. }
  370. pch++;
  371. pch = SkipWhite( pch );
  372. }
  373. // If we didn't find a mapping and a default was specified, use
  374. // the default URL
  375. //
  376. if ( pchPoint )
  377. {
  378. pch = pchPoint;
  379. goto Found;
  380. }
  381. if ( pchDefault )
  382. {
  383. pch = pchDefault;
  384. goto Found;
  385. }
  386. DebugTrace ("Dav: no mapping found for (%d, %d)\n", x, y);
  387. goto Exit;
  388. Found:
  389. // pch should point to the white space immediately before the URL
  390. //
  391. pch = SkipWhite( pch );
  392. pchStart = pch;
  393. pch = SkipNonWhite( pch );
  394. // Determine the length of the URL and copy it out
  395. //
  396. cchUrl = static_cast<UINT>(pch - pchStart);
  397. if ( cchUrl >= cchBuf )
  398. return FALSE;
  399. CopyMemory (pszRedirect, pchStart, cchUrl);
  400. *(pszRedirect + cchUrl) = 0;
  401. *pfRedirect = TRUE;
  402. DebugTrace ("Dav: mapping for (%d, %d) is %hs\n", x, y, pszRedirect);
  403. Exit:
  404. return fRet;
  405. }
  406. BOOL
  407. FIsMapProcessed (
  408. LPCSTR lpszQueryString,
  409. LPCSTR lpszUrlPrefix,
  410. LPCSTR lpszServerName,
  411. LPCSTR pszMap,
  412. BOOL * pfRedirect,
  413. LPSTR pszRedirect,
  414. UINT cchBuf)
  415. {
  416. INT x = 0;
  417. INT y = 0;
  418. LPCSTR pch = lpszQueryString;
  419. // Ensure the *pfRedirect is initialized
  420. //
  421. Assert( pfRedirect );
  422. *pfRedirect = FALSE;
  423. // If there is no query string, I don't think we want to process
  424. // the file as if it were a .map request.
  425. //
  426. if ( pch == NULL )
  427. return TRUE;
  428. // Get the x and y cooridinates of the mouse click on the image
  429. //
  430. x = strtoul( pch, NULL, 10 );
  431. // Move past x and any intervening delimiters
  432. //
  433. while ( isdigit( *pch ))
  434. pch++;
  435. while ( *pch && !isdigit( *pch ))
  436. pch++;
  437. y = strtoul( pch, NULL, 10 );
  438. // Search the map file
  439. //
  440. if ( !FSearchMapFile( pszMap,
  441. x,
  442. y,
  443. pfRedirect,
  444. pszRedirect,
  445. cchBuf))
  446. {
  447. DebugTrace ("Dav: FSearchMapFile() failed with %ld\n", GetLastError());
  448. return FALSE;
  449. }
  450. // If no redirected URL was passed back, then we are done.
  451. //
  452. if ( !*pfRedirect )
  453. {
  454. // Returning true does not indicate success, it really
  455. // just means that there were no processing errors
  456. //
  457. goto ret;
  458. }
  459. // If the found URL starts with a forward slash ("/foo/bar/doc.htm")
  460. // and it doesn't contain a bookmark ('#') then the URL is local and
  461. // we build a fully qualified URL to send back to the client. We assume
  462. // it's a fully qualified URL ("http://foo/bar/doc.htm") and send the
  463. // client a redirection notice to the mapped URL
  464. //
  465. if ( *pszRedirect == '/' )
  466. {
  467. CHAR rgch[MAX_PATH];
  468. UINT cch;
  469. UINT cchUri;
  470. if ( strlen(lpszUrlPrefix) + strlen(lpszServerName) >= MAX_PATH)
  471. return FALSE;
  472. // Build up the full qualification to the url
  473. //
  474. strcpy (rgch, lpszUrlPrefix);
  475. strcat (rgch, lpszServerName);
  476. // See how much we need to shif the URL by
  477. //
  478. cch = static_cast<UINT>(strlen (rgch));
  479. cchUri = static_cast<UINT>(strlen (pszRedirect));
  480. // If they haven't passed us enough buffer to copy
  481. // the redirect url, fail. Add one to the counts for the
  482. // terminating NULL character
  483. //
  484. if (cchBuf < (cchUri + cch + 1))
  485. return FALSE;
  486. MoveMemory (pszRedirect + cch, pszRedirect, cchUri + 1);
  487. CopyMemory (pszRedirect, rgch, cch);
  488. }
  489. ret:
  490. return TRUE;
  491. }