001package algs55; // section 5.5
002import stdlib.*;
003/* ***********************************************************************
004 *  Compilation:  javac RunLength.java
005 *  Execution:    java RunLength - < input.txt   (compress)
006 *  Execution:    java RunLength + < input.txt   (expand)
007 *  Dependencies: BinaryIn.java BinaryOut.java
008 *
009 *  Compress or expand binary input from standard input using
010 *  run-length encoding.
011 *
012 *  % java BinaryDump 40 < 4runs.bin
013 *  0000000000000001111111000000011111111111
014 *  40 bits
015 *
016 *  This has runs of 15 0s, 7 1s, 7 0s, and 11 1s.
017 *
018 *  % java RunLength - < 4runs.bin | java HexDump
019 *  0f 07 07 0b
020 *  4 bytes
021 *
022 *************************************************************************/
023
024public class RunLength {
025        private static BinaryIn binaryIn;
026        private static BinaryOut binaryOut;
027        private static final int R   = 256;
028        private static final int lgR = 8;
029
030        public static void expand() {
031                boolean b = false;
032                while (!binaryIn.isEmpty()) {
033                        int run = binaryIn.readInt(lgR);
034                        for (int i = 0; i < run; i++)
035                                binaryOut.write(b);
036                        b = !b;
037                }
038                binaryOut.close();
039        }
040
041        public static void compress() {
042                char run = 0;
043                boolean old = false;
044                while (!binaryIn.isEmpty()) {
045                        boolean b = binaryIn.readBoolean();
046                        if (b != old) {
047                                binaryOut.write(run, lgR);
048                                run = 1;
049                                old = !old;
050                        }
051                        else {
052                                if (run == R-1) {
053                                        binaryOut.write(run, lgR);
054                                        run = 0;
055                                        binaryOut.write(run, lgR);
056                                }
057                                run++;
058                        }
059                }
060                binaryOut.write(run, lgR);
061                binaryOut.close();
062        }
063
064
065        public static void main(String[] args) {
066                String txtFile = "data/4runs.bin";
067                String binFile = "4runsOut.bin";
068                //args = new String[] { "+" }; binaryIn = new BinaryIn(binFile); binaryOut = new BinaryOut();
069                args = new String[] { "-" }; binaryIn = new BinaryIn(txtFile); binaryOut = new BinaryOut(binFile);
070                if      (args[0].equals("-")) compress();
071                else if (args[0].equals("+")) expand();
072                else throw new Error("Illegal command line argument");
073        }
074
075}