\documentclass[a4paper]{article} 
\input{head}
\begin{document}

%-------------------------------
%	TITLE SECTION
%-------------------------------

\fancyhead[C]{}
\hrule \medskip % Upper rule
\begin{minipage}{0.295\textwidth} 
\raggedright
\footnotesize
Andrew Hayes \hfill\\   
21321503 \hfill\\
a.hayes18@nuigalway.ie
\end{minipage}
\begin{minipage}{0.4\textwidth} 
\centering 
\large 
CT255 Assignment 3\\ 
\normalsize 
Steganography\\ 
\end{minipage}
\begin{minipage}{0.295\textwidth} 
\raggedleft
\today\hfill\\
\end{minipage}
\medskip\hrule 
\bigskip

%-------------------------------
%	CONTENTS
%-------------------------------

\section{Problem 1}
\subsection{Code}
\begin{lstlisting}[language=Java]
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.regex.Pattern;

public class Stegano1
{
    public static void main(String[] args) {
        // Strings to hold the arguments. mode is either A or E for "Add" or "Extract". 
        String mode, inputfile, outputfile, bitstring;  
        Boolean err = false;                                                    // Boolean to tell if the arguments were passed correctly or not 

        if (args.length > 1) {                                                  // checking that at least one argument was passed to main
            // assigning the mode & inputfile arguments
            mode = args[0];
            inputfile = args[1];
                
            if (inputfile.equals("")) {                                         // checking that an inputfile was provided (String was not empty)
                err = true;
            }
            else if ((mode.equals("A")) && (args.length > 3)){                  // checking if the mode is "Add" & that the number of arguments provided was greater than 3
                // assigning the outputfile & bitstring arguments
                outputfile = args[2];
                bitstring = args[3];
        
                if (outputfile.equals("") || bitstring.equals("")) {            // checking that neither the outputfile nor bitstring were empty strings
                    err = true;
                }
                else {
                    // hiding the bitstring
                    hide(inputfile, outputfile, bitstring);
                }
            }
            else if (mode.equals("E")){                                         // checking if the mode is "Extract"
                // retrieving (extracting) the bitstring from text   
                retrieve(inputfile);   
            }
            else {
                err = true;
            }
        }
        else {
            err = true;
        }
        
        if (err) {
            System.out.println();
            System.out.println("Use: Stegano1 <A:E><Input File><OutputFile><Bitstring>");
            System.out.println("Example to add a bitvector to a file: Stegano1 A inp.txt out.txt 0010101");
            System.out.println("Example to extract a bitvector from a file: Stegano1 E inp.txt");
            
        } 
    }
   
    // method to hide a bitstring in a copy the input file provided
    static void hide(String inpFile, String outFile, String bitString) {
        BufferedReader reader;                                                  // declaring a BufferedReader for the input file 
        BufferedWriter writer;                                                  // declaring a BufferedWriter for the output file
	
        try {
            // initialising the reader & writer to FileReaders of their respective files (inpFile & outFile)
            reader = new BufferedReader(new FileReader(inpFile));       
            writer = new BufferedWriter(new FileWriter(outFile));
            
            String line = reader.readLine();                                    // reading in the first line from the input file
            
            // will loop until there are no more lines to be read in from the input file (inpFile)
            while (line != null) {
               
                // if the bitString is not (yet) an empty String
                if (!bitString.equals("")) {

                    // if the first bit (char) of the bitString is 0
                    if (bitString.charAt(0) == '0') {                           // note: must use '' instead of "" for char literals
                        line = line.concat(" ");                                // concatenating a space to the end of the line (one space represents a 0)
                    }  
                    
                    // if the first bit of the bitString is 1
                    if (bitString.charAt(0) == '1') {
                        line = line.concat("  ");                               // concatenating two spaces to the end of the line (two spaces represents a 1)
                    }

                    // removing the first bit from the bitString now that it has been used
                    bitString = bitString.substring(1, bitString.length());     // replacing bitString with it's substring that goes from the second character to the last character
                }

                // writing the amended line to the output file
                writer.write(line);
                writer.newLine();

		        // reading the next line
		        line = reader.readLine();
            }

            // closing the reader & the writer
            reader.close();
            writer.close();
	    }

        // catching any IOExceptions
        catch (IOException e) {
	        e.printStackTrace();
	    }
    }
    
    // method to retrieve a hidden string from the input file provided
    static void retrieve(String inpFile) {
        BufferedReader reader;                                          // declaring a BufferedReader for the input file (inpFile)
        String message = "";

        try {
            reader = new BufferedReader(new FileReader(inpFile));       // initialising the reader to a FileReader of the input file (inpFile) 
            
            String line = reader.readLine();                            // reading in the first line from the input file
            
            // will loop until there are no more lines to be read in from the input file
            while (line != null) {

                // checking if the line ends in a space using a regular expression
                if (Pattern.matches(".* $", line)) {                    // (checking if the String line contains any amount of any characters, followed by a space followed by the end of a line)

                    // checking if the line ends in two spaces using a regular expression
                    if (Pattern.matches(".*  $", line)) {               // (checking if the String line contains any amount of any characters, followed by two spaces followed by the end of a line)
                        message = message.concat("1");                  // concatenating a "1" onto the message String (two spaces represent a "1")
                    }
                    else {                                              // essentially, this "else" means "if the line ends with one space but not two"
                        message = message.concat("0");                  // concatenating a "0" onto the message String (one space represents a "0")
                    }
                }
                else {                                                  // if the String does not end in a space, then there is no (more) message to read
                    break;
                }
                
                // reading the next line
	        	line = reader.readLine();
            }

            // closing in the reader
            reader.close();

            // checking if the message String is empty so that an error message can be printed if no hidden message was found
            if (message.equals("")) {
                message = "Error: No hidden message found!";
            }

            // printing out the message
            System.out.println(message);
	    } 
        // catching any IOExceptions
        catch (IOException e) {
	        e.printStackTrace();
	    }
    }
}
\end{lstlisting}

\subsection{Screenshot of Compilation \& Output}
\includegraphics[width = 15cm]{output1.png}
\bigskip

%------------------------------------------------

\section{Problem 2}
\subsection{Code}
\begin{lstlisting}[language=java]
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.regex.Pattern;

public class Stegano1
{
    public static void main(String[] args) {
        // Strings to hold the arguments. mode is either A or E for "Add" or "Extract". 
        String mode, inputfile, outputfile, bitstring;  
        Boolean err = false;                                                    // Boolean to tell if the arguments were passed correctly or not 

        if (args.length > 1) {                                                  // checking that at least one argument was passed to main
            // assigning the mode & inputfile arguments
            mode = args[0];
            inputfile = args[1];
                
            if (inputfile.equals("")) {                                         // checking that an inputfile was provided (String was not empty)
                err = true;
            }
            else if ((mode.equals("A")) && (args.length > 3)){                  // checking if the mode is "Add" & that the number of arguments provided was greater than 3
                // assigning the outputfile & bitstring arguments
                outputfile = args[2];
                bitstring = args[3];
        
                if (outputfile.equals("") || bitstring.equals("")) {            // checking that neither the outputfile nor bitstring were empty strings
                    err = true;
                }
                else {
                    // hiding the bitstring
                    hide(inputfile, outputfile, bitstring);
                }
            }
            else if (mode.equals("E")){                                         // checking if the mode is "Extract"
                // retrieving (extracting) the bitstring from text   
                retrieve(inputfile);   
            }
            else {
                err = true;
            }
        }
        else {
            err = true;
        }
        
        if (err) {
            System.out.println();
            System.out.println("Use: Stegano1 <A:E><Input File><OutputFile><Bitstring>");
            System.out.println("Example to add a bitvector to a file: Stegano1 A inp.txt out.txt 0010101");
            System.out.println("Example to extract a bitvector from a file: Stegano1 E inp.txt");
            
        } 
    }
   
    // method to hide a bitstring in a copy the input file provided
    static void hide(String inpFile, String outFile, String bitString) {
        // to encode 2 bits with just one symbol, i'm going to represent the binary digits as an analog represenation of the number it represents plus one
        // e.g., 00 will be represented as " " (1 space), 01 as "  " (2 spaces), 10 as "   " (3 spaces), and 11 as "    " (4 spaces)
        // the two bits are treated as a binary number, and then i add one to said binary number to get the number of spaces that will represent that number

        BufferedReader reader;                                                  // declaring a BufferedReader for the input file 
        BufferedWriter writer;                                                  // declaring a BufferedWriter for the output file
	
        try {
            // initialising the reader & writer to FileReaders of their respective files (inpFile & outFile)
            reader = new BufferedReader(new FileReader(inpFile));       
            writer = new BufferedWriter(new FileWriter(outFile));
            
            String line = reader.readLine();                                    // reading in the first line from the input file

            // checking if the number of bits in the bitstring is uneven, and if so, adding a '0' onto the end 
            if (bitString.length() % 2 != 0) { bitString = bitString.concat("0"); }
            
            // will loop until there are no more lines to be read in from the input file (inpFile)
            while (line != null) {
               
                // if the bitString is not (yet) an empty String
                if (!bitString.equals("")) {

                    // if the first 2-bit substring is 00, adding one space to the end of the line
                    if (bitString.substring(0,2).equals("00")) {
                        line = line.concat(" ");
                    }
                    // if the first 2-bit substring is 01, adding two spaces to the end of the line
                    else if (bitString.substring(0,2).equals("01")) {
                        line = line.concat("  ");
                    }
                    // if the first 2-bit substring is 10, adding three spaces to the end of the line
                    else if (bitString.substring(0,2).equals("10")) {
                        line = line.concat("   ");
                    }
                    // if the first 2-bit substring is 11, adding four spaces to the end of the line
                    else if (bitString.substring(0,2).equals("11")) {
                        line = line.concat("    ");
                    }
                    // removing the first two bits from the bitString now that they have been used
                    bitString = bitString.substring(2, bitString.length());     // replacing bitString with it's substring that goes from the third character to the last character
                }

                // writing the amended line to the output file
                writer.write(line);
                writer.newLine();

		        // reading the next line
		        line = reader.readLine();
            }

            // closing the reader & the writer
            reader.close();
            writer.close();
	    }

        // catching any IOExceptions
        catch (IOException e) {
	        e.printStackTrace();
	    }
    }
    
    // method to retrieve a hidden string from the input file provided
    static void retrieve(String inpFile) {
        BufferedReader reader;                                                  // declaring a BufferedReader for the input file (inpFile)
        String message = "";

        try {
            reader = new BufferedReader(new FileReader(inpFile));               // initialising the reader to a FileReader of the input file (inpFile) 
            
            String line = reader.readLine();                                    // reading in the first line from the input file
            
            // will loop until there are no more lines to be read in from the input file
            while (line != null) {
                // checking if the line ends in a space using a regular expression
                if (Pattern.matches(".* $", line)) {                            // (checking if the String line contains any amount of any characters, followed by a space followed by the end of a line)

                    if (Pattern.matches(".*    $", line)) {                     // checking if the line ends in four spaces using a regular expression
                        message = message.concat("11");                         // concatenating "11" onto the end of the message String (four spaces represents "11")
                    }
                    else if (Pattern.matches(".*   $", line)) {                 // checking if the line ends in three spaces using a regular expression
                        message = message.concat("10");                         // concatenating "10" onto the end of the message String (three spaces represents "10")
                    }
                    else if (Pattern.matches(".*  $", line)) {                  // (checking if the String line contains any amount of any characters, followed by two spaces followed by the end of a line)
                        message = message.concat("01");                         // concatenating a "1" onto the message String (two spaces represent a "1")
                    }
                    else {                                                      // essentially, this "else" means "if the line ends with one space but not two"
                        message = message.concat("00");                         // concatenating a "0" onto the message String (one space represents a "0")
                    }
                }
                else {                                                          // if the String does not end in a space, then there is no (more) message to read
                    break;
                }
                
                // reading the next line
	        	line = reader.readLine();
            }

            // closing in the reader
            reader.close();

            // checking if the message String is empty so that an error message can be printed if no hidden message was found
            if (message.equals("")) {
                message = "Error: No hidden message found!";
            }

            // printing out the message
            System.out.println(message);
	    } 
        // catching any IOExceptions
        catch (IOException e) {
	        e.printStackTrace();
	    }
    }
}
\end{lstlisting}
\subsection{Output}
\includegraphics[width = 15cm]{output2.png}

\end{document}
