    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    }