LinkChecker.java
上传用户:afrynkmhm
上传日期:2007-01-06
资源大小:1262k
文件大小:8k
源码类别:

编译器/解释器

开发平台:

Others

  1. import java.io.*;
  2. import antlr.*;
  3. import java.util.Hashtable;
  4. class LinkChecker implements LinkListener {
  5.   /** Which directory is the document in? */
  6.   private String directory = "."; // default to current dir
  7.   /** Which document are we to process? */
  8.   private String document;
  9.   /** Record which files we have seen so that we don't get into an
  10.    *  infinite loop and for efficiency.  The absolute path is stored here
  11.    *  to uniquely identify the files.  That is, a file can be arrived
  12.    *  at from many different locations such as help.html from .
  13.    *  and ../help.html from a directory below.
  14.    *
  15.    *  This table is shared by all instances of LinkChecker.
  16.    */
  17.   private static Hashtable visited = new Hashtable(100);
  18.   /** A table of the images visited by any document; a cache of correctness */
  19.   private static Hashtable imgVisited = new Hashtable(100);
  20.   private static int recursionDepth = 0;
  21.   private static final String separator = "/"; // not OS sensitive in HTML
  22.   private static final String localSeparator =
  23.   System.getProperty("file.separator");
  24.   
  25.   public LinkChecker(String document) {
  26. this.document = document;
  27. this.directory = pathMinusFile(document);
  28.   }  
  29. public boolean checkLinkRules(String fName, int line) {
  30. // Check case of path (check for UNIX compatibility on a PC)!
  31. String offensive = offensivePathMember(directory + separator + fName);
  32. if (offensive != null) {
  33. String file="";
  34. try {
  35. File f = new File(offensive);
  36. file = f.getCanonicalPath();
  37. error("Case mismatch in reference " + fName + ":"+
  38. System.getProperty("line.separator")+"treal name is "+
  39. fileMinusPathLocal(file)+System.getProperty("line.separator")+
  40. "treal absolute path is "+file, line);
  41. return false;
  42. }
  43. catch (IOException io) {
  44. error("internal error: cannot get canonical name for "+offensive, line);
  45. }
  46. }
  47. if (new File(fName).isAbsolute()) {
  48. error("Reference to " + fName + " with absolute path", line);
  49. return false;
  50. }
  51. return true;
  52. }
  53. public void doCheck() throws IOException {
  54. if ( !document.endsWith(".html") ) {
  55. return;
  56. }
  57. // prevent infinite recursion to this file
  58. if (visited(document)) {
  59. return;
  60. }
  61. visit(document);
  62. recursionDepth++;
  63. FileReader f = new FileReader(document);
  64. LinkExtractor lexer = new LinkExtractor(f);
  65. lexer.addLinkListener(this);
  66. // this will parse whole file since all tokens are skipped
  67. lexer.nextToken();
  68. recursionDepth--;
  69. }
  70.   public void error(String err, int line) {
  71. String d="<internal error>";
  72. try {
  73. File f = new File(document);
  74. d = f.getCanonicalPath();
  75. }
  76. catch (IOException io) {
  77. System.err.println("internal error: cannot find file that has error");
  78. System.exit(0);
  79. }
  80. System.err.println(d+":"+line+":"+System.getProperty("line.separator")+"t"+err);
  81.   }  
  82.   public static boolean fileAbsolute(String path) {
  83. return path.startsWith("/") || path.charAt(1)==':';
  84.   }  
  85.   /** Return file from end of HTML path; i.e., use '/' separator */
  86.   public static String fileMinusPath(String f) {
  87. int endOfPath = f.lastIndexOf(separator);
  88. if ( endOfPath == -1 ) {
  89.   return f; // no path found
  90. }
  91. return f.substring(endOfPath+1);
  92.   }    
  93.   /** Return file from end of locally correct path; i.e., use '/' or '' separator */
  94.   public static String fileMinusPathLocal(String f) {
  95. int endOfPath = f.lastIndexOf(localSeparator);
  96. if ( endOfPath == -1 ) {
  97.   return f; // no path found
  98. }
  99. return f.substring(endOfPath+1);
  100.   }        
  101.   public static boolean fileProtocolURL(String target) {
  102. return target.indexOf("://") == -1 &&
  103. !target.startsWith("mailto:") &&
  104. !target.startsWith("news:");
  105.   }    
  106.   public static String getParent(String path) {
  107. int index = path.lastIndexOf(separator);
  108. if (index < 0) {
  109.   return null;
  110. }
  111. if ( !fileAbsolute(path) || path.indexOf(separator) != index ) {
  112.   return path.substring(0, index);
  113. }
  114. if (index < path.length() - 1) {
  115.   return path.substring(0, index + 1);
  116. }
  117. return null;
  118.   }  
  119. public void hrefReference(String target, int line) {
  120. // System.out.println(document+":"+line+": href to "+target);
  121. // recursively check the target document unless non-file ref
  122. if (fileProtocolURL(target)) {
  123. // prune off any #name reference on end of file
  124. int pound = target.indexOf('#');
  125. String path = target;
  126. if (pound != -1) {
  127. path = target.substring(0, pound); // rip off #name on end, leave file
  128. if (path.length() == 0) {
  129. return; // ref to name in this file
  130. }
  131. }
  132. // first check existence on disk
  133. File f = new File(directory + separator + path);
  134. if (!f.exists()) {
  135. error("Reference to missing file " + path, line);
  136. return;
  137. }
  138. // check the case
  139. checkLinkRules(path, line);
  140. try {
  141. // Link is ok, now follow the link
  142. LinkChecker chk = new LinkChecker(directory + separator + path);
  143. chk.doCheck();
  144. } catch (IOException io) {
  145. error("Document does not exist: " + target, line);
  146. }
  147. }
  148. }
  149.   public static boolean imageLinkIsOk(String file) throws IOException {
  150. File f = new File(file);
  151. file = f.getCanonicalPath();
  152. Boolean b = (Boolean)imgVisited.get(file);
  153. if ( b!=null ) {
  154. return b.booleanValue();
  155. }
  156. return false;
  157.   }            
  158. public void imageReference(String imageFileName, int line) {
  159. // first check if we have seen this exact file
  160. try {
  161. if (imageLinkIsOk(directory+separator+imageFileName)) {
  162. return;
  163. }
  164. File f = new File(directory + separator + imageFileName);
  165. if (!f.exists()) {
  166. error("Reference to missing file " + imageFileName, line);
  167. return;
  168. }
  169. if (checkLinkRules(imageFileName, line)) {
  170. visitImage(directory+separator+imageFileName);
  171. }
  172. } catch (IOException io) {
  173. if (!(io instanceof FileNotFoundException)) {
  174. System.err.println("internal error: " + io.getMessage());
  175. }
  176. }
  177. }
  178. /** Given a path to a file or dir, is the case of the reference
  179.    *  the same as the actual path on the disk?  This is only
  180.    *  meaningful on a PC which is case-insensitive (not a real
  181.    *  file system).
  182.    *
  183.    *  Returns null if there is nothing offensive and the file exists.
  184.    *  Returns offending file/dir if it does not exist or
  185.    *  it has there is a case mismatch for it.  The last file is checked
  186.    *  first followed by the parent directory, recursively, all the way
  187.    *  to the absolute or relative path root in that String; i.e., we parse
  188.    *  from right to left.
  189.    *
  190.    *  Because the File object won't actually go get the real filename
  191.    *  from the disk so we can compare, we must get a directory listing
  192.    *  of the directory and then look for the referenced file or dir.
  193.    *  For example, for "./images/logo.gif" we would check "./images" dir
  194.    *  listing for "logo.gif" with the appropriate case and then check
  195.    *  directory "." for a dir called images with the right case.  When
  196.    *  no parent exists, we can stop looking for case problems.
  197.    */
  198. public static String offensivePathMember(String fName) {
  199. // System.out.println("caseMismatch(" + fName + ")");
  200. // have we reached the root? (stopping condition)
  201. if (fName==null || getParent(fName) == null) {
  202. return null;
  203. }
  204. String parent = getParent(fName);
  205. fName = fileMinusPath(fName);
  206. File f = new File(parent);
  207. String[] parentFiles = f.list();
  208. // System.out.println("checking dir " + parent + " for " + fName);
  209. // handle weird stuff like "c:/doc/../foo"; skip this parent dir
  210. if ( fName.equals("..") ) {
  211. return offensivePathMember(getParent(parent));
  212. }
  213. for (int i = 0; i < parentFiles.length; i++) {
  214. // System.out.println("is it " + parentFiles[i] + "?");
  215. if (parentFiles[i].equalsIgnoreCase(fName)) {
  216. if (!parentFiles[i].equals(fName)) {
  217. // System.out.println("case mismatch " + fName + " in " + parent);
  218. return parent + separator + fName;
  219. }
  220. // found a match, verify parent is ok
  221. return offensivePathMember(parent);
  222. }
  223. }
  224. // System.out.println("can't find " + fName + " in " + parent);
  225. return parent + separator + fName;
  226. }
  227.   public static String pathMinusFile(String f) {
  228. int endOfPath = f.lastIndexOf(separator);
  229. if ( endOfPath == -1 ) {
  230.   return "."; // no path found: use current directory
  231. }
  232. return f.substring(0, endOfPath);
  233.   }  
  234.   public static void visit(String file) throws IOException {
  235. File f = new File(file);
  236. file = f.getCanonicalPath();
  237. visited.put(file, new Boolean(true));
  238.   }    
  239.   public static boolean visited(String file) throws IOException {
  240. File f = new File(file);
  241. file = f.getCanonicalPath();
  242. return visited.get(file) != null;
  243.   }    
  244.   public static void visitImage(String file) throws IOException {
  245. File f = new File(file);
  246. file = f.getCanonicalPath();
  247. // System.out.println("caching image "+file);
  248. imgVisited.put(file, new Boolean(true));
  249.   }            
  250. }