java/ch/wlkl/wsh/War.java

package ch.wlkl.wsh;

import java.io.File;
import java.io.IOException;
import java.util.regex.Pattern;

public class War extends Run {
    public static final String Mark = "]";
    public static final String Begin = "beg ";
    public static final String End = "end ";
    final static Option argAna = new Option("", "Cfz");
    
    private final Read<String> dir;
    private final Read<String> read;
    private final Write<String> write;
    

    File wFile = null; 
    File home = new File(".");
    boolean fromZos = false;
    Pattern filter = null;

    int iFiles = 0;
    int oFiles = 0;

    public War (Read<String> dir, Read<String> read, Write<String> write) {
        this.dir = dir == null ? new Dir() : dir;
        this.read = read == null ? new Cat<String>() : read;
        this.write = write == null ? new FileRW() : write;
        home = new File(".");
    }

    public War () {
        this(null, null, null);
    }

    public void run(String... args ) {
        iFiles = oFiles = 0;
        char fun = ' ';
        boolean started = false;
        String wFile = null;
        String [] ana = new String[2];

        if (argAna.analyze(args[0], ana) || ! ("cf".equals(ana[1]) || "xf".equals(ana[1])))
            fail("only cf and xf supported not " + args[0]);
        fun = ana[1].charAt(0);

        if (argAna.analyze(args[1], ana) || (wFile = ana[1]) == null)
            fail("file name expected not " + args[1]);

        for (int ax = 2; ax < args.length; ax++) {
            if (argAna.analyze(args[ax], ana)) {
                if ("C".equals(ana[0]))
                    home = new File(ana[1]);
                else if ("f".equals(ana[0]))
                    filter = "".equals(ana[1]) ? null : Pattern.compile(ana[1]);
                else if ("z".equals(ana[0]))
                    fromZos = ! "0".equals(ana[1]);
                else
                    fail("bad opt " + ana[0]);
            } else if (fun == 'c') {
                if (! started) {
                    started = true;
                    write.reset(wFile);
                    write.open("w");
                }
                dir.reset(canonical(new File(home, ana[1])));
                dir.open("r");
                append(write, dir);
                dir.close();
            } else if (fun == 'x') {
                if (! started) {
                    started = true;
                    read.reset(wFile);
                    read.open("r");
                }
                extract(read);
            } else {
                fail("bad fun " + fun);
            }
        }
        if (fun == 'x') {
            if (started) 
                read.close();
            Env.env().write("extracted " + oFiles + " of " + iFiles + " files from " + wFile);
        } else {
            if (started) 
                write.close();
            Env.env().write("added " + oFiles + " of " + iFiles + " files to " + wFile);
        }
    }

    
    public String filter(String in) {
        if (fromZos) {
            in = in.replace('.', '/').replaceFirst("\\(", "/");
            if (in.charAt(in.length()-1) == ')') 
                in = in.substring(0, in.length()-1);
        }
        return filter == null || filter.matcher(in).matches() ? in : null;
    }
    
    void append(Write<String> w, String name) {
        String line;
        String wNm = name.startsWith(canonical(home)) ? name.substring(canonical(home).length()+1) : name;
        w.write(Mark + Begin + wNm);
        read.reset(name);
        read.open("r");
        while (null != (line = read.read())) {
            w.write(line.startsWith(War.Mark) ? War.Mark + line : line ); 
        }
        w.write(Mark + End + wNm);
        read.close();
        oFiles ++ ;
    }

    void append(Write<String> w, Read<String> dir) {
        String name;
        while (null != (name = dir.read())) {
            iFiles ++ ;
            if (filter(name) != null)
                append(w, name); 
        }
    }

    String extract(Read<String> r, Write<String> w)  {
        iFiles ++;
        if (w != null)
            oFiles ++;
        while (true) {
            String line = r.read();
            if (line == null)
                return null;
            if (line.startsWith(War.Mark)) {            
                if (line.startsWith(War.Mark, War.Mark.length())) 
                    line = line.substring(War.Mark.length());
                else
                    return line;
            }
            if (w != null)
                w.write(line);
        }
    }
            
    void extract(Read<String> r) {
        String line;
        String name = null;
        String out;
        int errs = 0;
        
        while (null != (line = r.read())) {
            if (! line.startsWith(War.Mark) || ! line.startsWith(War.Begin, War.Mark.length())) {
                String l2 = r.read();
                if (l2 == null && line.equals(String.valueOf((char) 0x1a)))
                    break;
                say("data outside file line after " + name + " len " + line.length()+ " hex: " + Strings.hex(line) + " ascii: " + line + " befor: " + l2);
                if (++errs > 99)
                    fail("too many errors");
            } else {
                name = Parser.skipScan(line.substring(War.Begin.length() + War.Mark.length()), Parser.space, Parser.notSpace);
                if (name == null)
                    fail("begin without name");
                if (null == (out = filter(name))) { 
                    line = extract(r, null);
                } else {
                    write.reset(new File(home, out).getPath());
                    write.open("w");
                    line = extract(r, write);
                    write.close();
                }
                if (! line.startsWith(War.Mark) || ! line.startsWith(War.End, War.Mark.length())) 
                    fail("end expected: " + line);
                else if (! name.equals(Parser.skipScan(line.substring(War.End.length() + War.Mark.length()), Parser.space, Parser.notSpace)))
                    fail("begin name " + name + " mismatches end " + line);
            }
        }
    }
    
    public static String canonical(String name) {
        return canonical(new File(name));
    }

    public static String canonical(File file) {
        try {
            return file.getCanonicalPath();
        } catch (IOException e) {
            sFail("canonical of " + file + " caught " + e);
            return null;
        }
    }

    public static void main(String... args) {
        War w = new War();
        Env.env().write("begin War " + args.length + " " + (args.length > 0 ? args[0] : ""));
        w.run(args);
        Env.env().write("end   War " + args.length + " " + (args.length > 0 ? args[0] : ""));
        
    }
    
}