001 /* Copyright 2000, 2001, Compaq Computer Corporation */ 002 003 package javafe.filespace; 004 005 006 import java.io.*; 007 import java.util.zip.*; 008 import java.util.Enumeration; 009 010 import javafe.genericfile.*; 011 012 013 /** 014 * This module encapsulates how to convert from a Java path-component 015 * name to the hierarchical filespace it denotes.<p> 016 * 017 * Filespaces are represented by Trees whose node's data fields contain 018 * (non-null) GenericFiles that represent the corresponding files. 019 * E.g., the node at X.Y.Z represents a file with pathname ./X/Y/Z in 020 * the hierarchy of the path component.<p> 021 * 022 * Changes made to the underlying file system may or may not be 023 * reflected in the returned filespaces.<p> 024 */ 025 026 public class PathComponent { 027 028 /*************************************************** 029 * * 030 * Creation of filespaces: * 031 * * 032 **************************************************/ 033 034 /** 035 * Create an empty filespace, containing only a root directory 036 */ 037 //@ ensures \result != null; 038 public static Tree empty() { 039 return new LeafTree( 040 new UnopenableFile("<root of the empty filesystem>", 041 true)); 042 } 043 044 045 /** 046 * Convert from a path-component name to the filespace it denotes.<p> 047 * 048 * Throws an IOException if any errors occur while initially 049 * scanning the component. Component must be non-null. The result 050 * is always a non-null filespace.<p> 051 * 052 * 053 * If complain is set, open will throw IOExceptions if the 054 * path component does not exist, or if it is not a directory or a 055 * zipfile. If complain is not set, then an empty filespace will 056 * be returned in these situations. Either way, IOExceptions will 057 * still be thrown if an error occurs reading an actual file or 058 * directory.<p> 059 * 060 * 061 * Note: changes to the filesystem named by component may or may 062 * not be reflected in the returned Tree.<p> 063 */ 064 //@ requires component != null; 065 //@ ensures \result != null; 066 public static Tree open(String component, boolean complain) 067 throws IOException { 068 // Make sure component refers to an existing file: 069 File root = new File(component); 070 if (!root.exists()) { 071 if (complain) 072 throw new IOException("no such file: " + component); 073 else 074 return empty(); 075 } 076 077 // Attempt to get the filespace contained in root 078 Tree filespace = null; 079 try { 080 if (isZipFilename(component)) 081 filespace = new ZipTree(root); 082 else if (root.isDirectory()) 083 filespace = new FileTree(root); 084 } catch (ZipException E) { 085 throw new IOException(component + ": unable to process zipfile: " 086 + E.getMessage()); 087 } catch (IOException E) { 088 throw new IOException("unable to open/read file: " 089 + E.getMessage()); 090 } 091 092 // Complain if component is not a directory or a zipfile: 093 if (filespace == null) { 094 if (complain) 095 throw new IOException("invalid classpath component: " 096 + component); 097 else 098 return empty(); 099 } 100 101 return filespace; 102 } 103 104 /** 105 * Does a filename indicate that it is in zip format? <p> 106 * 107 */ 108 //@ requires name != null; 109 protected static boolean isZipFilename(String name) { 110 return name.endsWith(".zip") || name.endsWith(".jar"); 111 } 112 113 114 /*************************************************** 115 * * 116 * Debugging functions: * 117 * * 118 **************************************************/ 119 120 /** A simple test driver */ 121 //@ requires \nonnullelements(args); 122 public static void main(String[] args) throws IOException { 123 // Check usage: 124 if (args.length<1 || args.length>2) { 125 System.out.println("PathComponent: usage <path component> " 126 + "[<pathname>]"); 127 return; 128 } 129 130 /* 131 * Create a new filespace from the path component args[0]: 132 */ 133 Tree T; 134 try { 135 T = open(args[0], false); 136 } catch (IOException E) { 137 System.out.println("Caught " + E); 138 return; 139 }; 140 141 // If pathname given, try to print out that file then exit: 142 if (args.length==2) { 143 String pathname = args[1]; 144 145 // Strip off any leading '/'s: 146 while (pathname.length()>0 && pathname.charAt(0)=='/') 147 pathname = pathname.substring(1,pathname.length()); 148 149 // Strip off any trailing '/'s: 150 while (pathname.length()>0 && 151 pathname.charAt(pathname.length()-1)=='/') 152 pathname = pathname.substring(0,pathname.length()-1); 153 154 Tree F = T.getQualifiedChild(pathname, '/'); 155 if (F==null) { 156 System.out.println("No such file: " + args[1]); 157 return; 158 } 159 160 InputStream I = ((GenericFile)F.data).getInputStream(); //@ nowarn Cast,Null; 161 for (;;) { 162 int next = I.read(); 163 if (next<0) 164 return; 165 166 System.out.write(next); 167 } 168 } 169 170 // T.print(""); 171 172 // Otherwise, list all the files in the filespace by their 173 // distinctive names, indicating which are directories and 174 // giving their modification times 175 Enumeration E = new TreeWalker(T); 176 while (E.hasMoreElements()) { 177 Tree node = (Tree)E.nextElement(); 178 GenericFile file = (GenericFile)node.data; //@ nowarn Cast; 179 //@ assume file != null; 180 181 System.out.print(file.getHumanName() + " "); 182 if (file.lastModified()==0L) 183 System.out.print("(unknown) "); 184 else 185 System.out.print("(" + file.lastModified() + ") "); 186 if (file.isDirectory()) 187 System.out.print("[D] "); 188 189 System.out.println(); 190 } 191 } 192 }