diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20e8d28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# ignore compiled Java class files +*.class \ No newline at end of file diff --git a/MorseCodeTranslatorDemo.java b/MorseCodeTranslatorDemo.java new file mode 100644 index 0000000..35469ba --- /dev/null +++ b/MorseCodeTranslatorDemo.java @@ -0,0 +1,65 @@ +import morseCodeTranslator.*; +import java.io.IOException; +import java.util.Scanner; +import java.io.File; +import java.io.FileNotFoundException; + +/** + * Demo to demonstrate use of MorseCodeTranslator package. + * Compile and run this file to see the translator in action. + */ +public class MorseCodeTranslatorDemo { + public static void main(String[] args) { + + File outputDir; // output file directory + + // run valid input files + try { + // make output directory + outputDir = new File("output"); + if (outputDir.exists() || outputDir.mkdir()) { + // translate sample files (no exceptions should be thrown) + MorseCodeTranslator.translateFile("input_files/sampleFile1.morsecode", "output/sampleOut1.translation"); + MorseCodeTranslator.translateFile("input_files/sampleFile2.morsecode", "output/sampleOut2.translation"); + MorseCodeTranslator.translateFile("input_files/emptyFile.morsecode", "output/emptyOutput.translation"); + MorseCodeTranslator.translateFile("input_files/allWhiteSpace.morsecode", "output/allWhiteSpace.translation"); + + // print output files to console + for (File file : outputDir.listFiles()) { + Scanner fileScanner = new Scanner(file); + System.out.println("\n" + file.getName() + ":"); + while (fileScanner.hasNextLine()) { + System.out.println(fileScanner.nextLine()); + } + fileScanner.close(); + } + } + else { + System.out.println("Cannot create output directory"); + } + } + catch (MorseCodeTranslatorException | FileNotFoundException e) { + e.printStackTrace(); + } + + // run invalid input files + translateInvalidFile("input_files/nonExistentFile.morsecode", "output/shouldNotExist.translation"); + translateInvalidFile("input_files/invalidInput.morsecode", "output/invalid1.translation"); + translateInvalidFile("input_files/invalidInput2.morsecode", "output/invalid2.translation"); + translateInvalidFile("input_files/invalidInput3.morsecode", "output/invalid3.translation"); + } + + /** + * Runs MorseCodeTranslator.translateFile() on an input file that's intended to be + * invalid and prints exception. + */ + private static void translateInvalidFile(String inputFileName, String outputFileName) { + try { + MorseCodeTranslator.translateFile(inputFileName, outputFileName); + } + catch (MorseCodeTranslatorException e) { + System.out.println("\nSuccessfully caught exception:"); + System.out.println(e); + } + } +} \ No newline at end of file diff --git a/input_files/allWhiteSpace.morsecode b/input_files/allWhiteSpace.morsecode new file mode 100644 index 0000000..2f2fed0 --- /dev/null +++ b/input_files/allWhiteSpace.morsecode @@ -0,0 +1,2 @@ +|||||||||| +|||||| \ No newline at end of file diff --git a/input_files/emptyFile.morsecode b/input_files/emptyFile.morsecode new file mode 100644 index 0000000..e69de29 diff --git a/input_files/invalidInput.morsecode b/input_files/invalidInput.morsecode new file mode 100644 index 0000000..074045a --- /dev/null +++ b/input_files/invalidInput.morsecode @@ -0,0 +1 @@ +..-.||..||.-?..||. \ No newline at end of file diff --git a/input_files/invalidInput2.morsecode b/input_files/invalidInput2.morsecode new file mode 100644 index 0000000..fcaec5d --- /dev/null +++ b/input_files/invalidInput2.morsecode @@ -0,0 +1 @@ +--||---|-.. \ No newline at end of file diff --git a/input_files/invalidInput3.morsecode b/input_files/invalidInput3.morsecode new file mode 100644 index 0000000..8ee3589 --- /dev/null +++ b/input_files/invalidInput3.morsecode @@ -0,0 +1 @@ +-..||....||-.-.-||. \ No newline at end of file diff --git a/input_files/sampleFile1.morsecode b/input_files/sampleFile1.morsecode new file mode 100644 index 0000000..3593895 --- /dev/null +++ b/input_files/sampleFile1.morsecode @@ -0,0 +1,7 @@ +.-||-...||-.-.||-..||.||..-.||--.||....||..||.---||-.-||.-..||--||-. +---||.--.||--.-||.-.||...||-||..-||...-||.--||-..-||-.--||--.. +-----||.----||..---||...--||....-||.....||-....||--...||---.. +----.||.-.-.-||--..--||..--..||-...- + +-..||---||--. +....||.||.-..||.-..||---||||.--||---||.-.||.-..||-.. \ No newline at end of file diff --git a/input_files/sampleFile2.morsecode b/input_files/sampleFile2.morsecode new file mode 100644 index 0000000..8ee8b4f --- /dev/null +++ b/input_files/sampleFile2.morsecode @@ -0,0 +1 @@ +--||---||.-.||...||.||||-.-.||---||-..||. \ No newline at end of file diff --git a/morseCodeTranslator/InputFileIOException.java b/morseCodeTranslator/InputFileIOException.java new file mode 100644 index 0000000..5faf586 --- /dev/null +++ b/morseCodeTranslator/InputFileIOException.java @@ -0,0 +1,25 @@ +package morseCodeTranslator; + +/** + * Exception raised when an IOException occurs while reading a morse + * code input file. + */ +public class InputFileIOException extends MorseCodeTranslatorException { + + public InputFileIOException() { + super(); + } + + public InputFileIOException(String message) { + super(message); + } + + public InputFileIOException(String message, Throwable cause) { + super(message, cause); + } + + public InputFileIOException(Throwable cause) { + super(cause); + } + +} \ No newline at end of file diff --git a/morseCodeTranslator/InputFileNotFoundException.java b/morseCodeTranslator/InputFileNotFoundException.java new file mode 100644 index 0000000..ba80be7 --- /dev/null +++ b/morseCodeTranslator/InputFileNotFoundException.java @@ -0,0 +1,24 @@ +package morseCodeTranslator; + +/** + * Exception raised when the input morse code file is not found. + */ +public class InputFileNotFoundException extends MorseCodeTranslatorException { + + public InputFileNotFoundException() { + super(); + } + + public InputFileNotFoundException(String message) { + super(message); + } + + public InputFileNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public InputFileNotFoundException(Throwable cause) { + super(cause); + } + +} \ No newline at end of file diff --git a/morseCodeTranslator/InvalidMorseCodeInputException.java b/morseCodeTranslator/InvalidMorseCodeInputException.java new file mode 100644 index 0000000..74dbf4e --- /dev/null +++ b/morseCodeTranslator/InvalidMorseCodeInputException.java @@ -0,0 +1,25 @@ +package morseCodeTranslator; + +/** + * Exception raised when an any invalid morse code or characters is + * read from the morse code input file. + */ +public class InvalidMorseCodeInputException extends MorseCodeTranslatorException { + + public InvalidMorseCodeInputException() { + super(); + } + + public InvalidMorseCodeInputException(String message) { + super(message); + } + + public InvalidMorseCodeInputException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidMorseCodeInputException(Throwable cause) { + super(cause); + } + +} \ No newline at end of file diff --git a/morseCodeTranslator/MorseCodeDictionary.java b/morseCodeTranslator/MorseCodeDictionary.java new file mode 100644 index 0000000..20a406f --- /dev/null +++ b/morseCodeTranslator/MorseCodeDictionary.java @@ -0,0 +1,72 @@ +package morseCodeTranslator; + +import java.util.Map; +import java.util.HashMap; + +/** + * Class representing a dictionary of morse code + * strings to character translations. + */ +final class MorseCodeDictionary { + + /* + * Members + */ + + // mapping of morse code strings to their translated characters + // static so that we only create one instance of this + private static final Map morseCodeMap = new HashMap<>(); + + // initialize the morseCodeMap + static { + // ordered array of morse code strings + String[] morseCodeStrings = new String[] { + ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", + ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", + "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----", + ".----", "..---", "...--", "....-", ".....", "-....", "--...", + "---..", "----.", ".-.-.-", "--..--", "..--..", "-...-" + }; + // ordered array of morse code translation characters + char[] morseCodeChars = new char[] { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',', '?', '=' + }; + + // arrays are ordered such that: + // morseCodeStrings[i] translates to morseCodeChars[i] + + for (int i=0; i < morseCodeStrings.length; i++) { + morseCodeMap.put(morseCodeStrings[i], morseCodeChars[i]); + } + } + + // This class is meant to expose a static function, so the + // user only needs one instance of this class. + // Therefore the constructor private. + private MorseCodeDictionary() { + + } + + /* + * Public Functions + */ + + /** + * Returns character translation of the given morse code letter. + * @param morseCodeInput string containing a morse code letter + * @return translated char + * @throws InvalidMorseCodeInputException if given an invalid morse code + * string as parameter + */ + public static char getCharacter(String morseCodeInput) throws InvalidMorseCodeInputException { + Character msCharacter = morseCodeMap.get(morseCodeInput); + + // msCharacter will be null if we're given invalid input (input not in the morse code map) + if (msCharacter == null) + throw new InvalidMorseCodeInputException("Invalid morse code input: " + morseCodeInput); + + return msCharacter; + } +} \ No newline at end of file diff --git a/morseCodeTranslator/MorseCodeInput.java b/morseCodeTranslator/MorseCodeInput.java new file mode 100644 index 0000000..f699240 --- /dev/null +++ b/morseCodeTranslator/MorseCodeInput.java @@ -0,0 +1,89 @@ +package morseCodeTranslator; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * Class for reading a morse code input file. + */ +class MorseCodeInput { + + /* + * Members + */ + private BufferedReader fileReader; + private static final String inputFileDelimiter = "\\|\\|"; + + /* + * Public functions + */ + + /** + * MorseCodeInput constructor. + * @param inputFileName name of morse code input file + * @throws InputFileNotFoundException if input morse code + * file is not found + */ + public MorseCodeInput(String inputFileName) throws InputFileNotFoundException { + // initialize the file reader + try { + this.fileReader = new BufferedReader(new FileReader(inputFileName)); + } + catch (FileNotFoundException e) { + throw new InputFileNotFoundException("Input file \""+inputFileName+"\" not found"); + } + } + + /** + * Gets all morse code characters in a file. + * @return String array with all morse code characters. + * May contain '\n': this indicates a newline + * May contain empty strings: this indicates a space + */ + public String[] getMorseCodeCharacters() throws InputFileIOException { + // initialize array of morse code characters + String[] morseCodeCharacters = new String[0]; + + // parse the file + try { + // read in each line of input file + String line = this.fileReader.readLine(); + while (line != null) { + // split line into morse code character strings using delimiter + String[] lineCharacters = line.split(this.inputFileDelimiter); + morseCodeCharacters = this.concatArraysAndNewline(morseCodeCharacters, lineCharacters); + line = this.fileReader.readLine(); + } + + this.fileReader.close(); + } + catch (IOException e) { + throw new InputFileIOException("IOException occurred with the input file", e); + } + + return morseCodeCharacters; + } + + /* + * Helper functions + */ + + /** + * Concatenates two string arrays + a newline and returns the resulting array. + */ + private String[] concatArraysAndNewline(String[] array1, String[] array2) { + int a1Length = array1.length; + int a2Length = array2.length; + String[] resultArray = new String[a1Length + a2Length + 1]; + + // copy array1 and array2 into result array + System.arraycopy(array1, 0, resultArray, 0, a1Length); + System.arraycopy(array2, 0, resultArray, a1Length, a2Length); + // newline + resultArray[resultArray.length - 1] = "\n"; + + return resultArray; + } +} \ No newline at end of file diff --git a/morseCodeTranslator/MorseCodeOutput.java b/morseCodeTranslator/MorseCodeOutput.java new file mode 100644 index 0000000..477de00 --- /dev/null +++ b/morseCodeTranslator/MorseCodeOutput.java @@ -0,0 +1,68 @@ +package morseCodeTranslator; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; + +/** + * Class for outputting morse code translations to file. + */ +class MorseCodeOutput { + + /* + * Members + */ + private BufferedWriter fileWriter; + + /* + * Public Functions + */ + + /** + * MorseCodeOutput constructor. + * @param outputFileName name of file to output to + * @throws OutputFileIOException if an IOException occurs while + * trying to create the output file + */ + public MorseCodeOutput(String outputFileName) throws OutputFileIOException { + // initialize the file writer + try { + this.fileWriter = new BufferedWriter(new FileWriter(outputFileName)); + } + catch (IOException e) { + throw new OutputFileIOException("IOException occurred when initializing the output file", e); + } + } + + /** + * Outputs a given character to file. + * @param outputChar character to output + * @throws OutputFileIOException if an IOException occurs + * while writing to the output file + */ + public void outputCharacter(char outputChar) throws OutputFileIOException { + String outCharacter = Character.toString(outputChar); + try { + this.fileWriter.write(outCharacter); + } + catch(IOException e) { + throw new OutputFileIOException("IOException occurred when writing to the output file", e); + } + } + + /** + * Call this function to finish writing to the output file. + * @throws OutputFileIOException if an IOException occurs + * when trying to close the output file + */ + public void finishWriting() throws OutputFileIOException { + // close the fileWriter + try { + this.fileWriter.close(); + } + catch (IOException e) { + throw new OutputFileIOException("IOException occurred when closing the output file", e); + } + } + +} \ No newline at end of file diff --git a/morseCodeTranslator/MorseCodeTranslator.java b/morseCodeTranslator/MorseCodeTranslator.java new file mode 100644 index 0000000..2a5d0d4 --- /dev/null +++ b/morseCodeTranslator/MorseCodeTranslator.java @@ -0,0 +1,84 @@ +package morseCodeTranslator; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; + +// This is the only class that is exposed to the user of this package + +/** + * Translates morse code. + */ +public class MorseCodeTranslator { + + /* + * Members + */ + private static MorseCodeDictionary morseCodeDictionary; + + // This class is meant to expose a static function, so the + // user only needs one instance of this class. + // Therefore the constructor private. + private MorseCodeTranslator() { + + } + + /* + * Public Functions + */ + + /** + * Translates file containing morse code and writes the results to + * an output file. + * @param inputFileName name of input file containing morse code + * @param outputFileName intended name of output file + * @throws MorseCodeTranslatorException if any exception related to + * file input, file output, or morse code to character translation + * occurs. Specific exception inherited from MorseCodeTranslatorException + * will be thrown. + */ + public static void translateFile(String inputFileName, String outputFileName) throws MorseCodeTranslatorException { + + MorseCodeInput morseCodeInput = null; + MorseCodeOutput morseCodeOutput = null; + String[] morseCodeCharacters; + + try { + // initialize input and output, get array of morse code characters + morseCodeInput = new MorseCodeInput(inputFileName); + morseCodeCharacters = morseCodeInput.getMorseCodeCharacters(); + morseCodeOutput = new MorseCodeOutput(outputFileName); + + // translate morse code character strings into characters and output them + for (int i = 0; i < morseCodeCharacters.length; i++) { + String msCharacter = morseCodeCharacters[i]; + + // empty string indicates a space + if (msCharacter.length() == 0) { + morseCodeOutput.outputCharacter(' '); + } + // string "\n" indicates a newline + else if (msCharacter.length() == 1 && (char)msCharacter.charAt(0) == '\n') { + + if (i == morseCodeCharacters.length - 1) { + // suppress trailing newline at end of file + continue; + } + + morseCodeOutput.outputCharacter('\n'); + } + else { + // translate morse code string to character and output it + morseCodeOutput.outputCharacter(morseCodeDictionary.getCharacter(msCharacter.trim())); + } + } + morseCodeOutput.finishWriting(); + } + catch (MorseCodeTranslatorException e) { + // throw any caught exceptions to the user + throw e; + } + } +} \ No newline at end of file diff --git a/morseCodeTranslator/MorseCodeTranslatorException.java b/morseCodeTranslator/MorseCodeTranslatorException.java new file mode 100644 index 0000000..7b2144c --- /dev/null +++ b/morseCodeTranslator/MorseCodeTranslatorException.java @@ -0,0 +1,26 @@ +package morseCodeTranslator; + +// Using custom exceptions here to give user of MorseCodeTranslator useful +// exceptions that indicate any specific issues that occur during translation. + +/** + * Exception representing any exception specific to the MorseCodeTranslator + */ +public abstract class MorseCodeTranslatorException extends Exception { + + public MorseCodeTranslatorException() { + super(); + } + + public MorseCodeTranslatorException(String message) { + super(message); + } + + public MorseCodeTranslatorException(String message, Throwable cause) { + super(message, cause); + } + + public MorseCodeTranslatorException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/morseCodeTranslator/OutputFileIOException.java b/morseCodeTranslator/OutputFileIOException.java new file mode 100644 index 0000000..c46b9f7 --- /dev/null +++ b/morseCodeTranslator/OutputFileIOException.java @@ -0,0 +1,25 @@ +package morseCodeTranslator; + +/** + * Exception raised when an IOException occurs while writing to the + * translation output file. + */ +public class OutputFileIOException extends MorseCodeTranslatorException { + + public OutputFileIOException() { + super(); + } + + public OutputFileIOException(String message) { + super(message); + } + + public OutputFileIOException(String message, Throwable cause) { + super(message, cause); + } + + public OutputFileIOException(Throwable cause) { + super(cause); + } + +} \ No newline at end of file