//CipherStreamJava/src/main/java/com/mattrixwv/CipherStreamJava/monoSubstitution/BaseX.java //Mattrixwv // Created: 01-08-22 //Modified: 07-09-22 package com.mattrixwv.cipherstream.monosubstitution; import java.util.StringJoiner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mattrixwv.cipherstream.exceptions.InvalidCharacterException; import com.mattrixwv.cipherstream.exceptions.InvalidInputException; import com.mattrixwv.cipherstream.exceptions.InvalidBaseException; public class BaseX{ private static final Logger logger = LoggerFactory.getLogger(BaseX.class); private String inputString; //The string that needs encoded/decoded private String outputString; //The encoded/decoded string private int base; //The base that the number will be encoded at //Sets the input string private void setInputStringEncode(String inputString) throws InvalidInputException{ if(inputString == null){ throw new NullPointerException("Input cannot be null"); } logger.debug("Setting input string for encoding '{}'", inputString); this.inputString = inputString; if(this.inputString.isBlank()){ throw new InvalidInputException("Input must contain at least 1 letter"); } } private void setInputStringDecode(String inputString) throws InvalidCharacterException, InvalidInputException{ if(inputString == null){ throw new NullPointerException("Input cannot be null"); } logger.debug("Setting input string for decoding '{}'", inputString); //Create a string of valid 'numbers' logger.debug("Creating string of valid 'numbers'"); StringBuilder validNumbers = new StringBuilder(); for(int cnt = 0;cnt < base;++cnt){ String number = Integer.toString(cnt, base).toUpperCase(); logger.debug("Current number {}, converted {}", cnt, number); validNumbers.append(number); } //Remove all invalid characters logger.debug("Checking for invalid characters"); this.inputString = inputString.replaceAll("[^" + validNumbers.toString() + "\\s]", ""); //Throw an exception if there were any invalid characters if(!this.inputString.equals(inputString)){ throw new InvalidCharacterException("inputString cannot contain anything except numbers 0-" + Integer.toString(base - 1, base) + ", and whitespace"); } logger.debug("Cleaned input string '{}'", inputString); if(this.inputString.isBlank()){ throw new InvalidInputException("Input must contain at least 1 letter"); } } //Sets the numeric base private void setBase(int base) throws InvalidBaseException{ if(base <= 0){ throw new InvalidBaseException("Base cannot be a negative number"); } logger.debug("Setting base {}", base); this.base = base; } //Encode inputString, store it in outputString, and return it private String encode(){ logger.debug("Encoding"); //Encode every character in inputString StringJoiner output = new StringJoiner(" "); for(int cnt = 0;cnt < inputString.length();++cnt){ //Get the next character char ch = inputString.charAt(cnt); logger.debug("Working number {}", ch); //Encode the character to binary and add it to the output String convertedNum = Integer.toString(ch, base); output.add(convertedNum); logger.debug("Converted number {}", convertedNum); } //Save the output outputString = output.toString().toUpperCase(); logger.debug("Saving output string '{}'", outputString); //Return the output return outputString; } //Decode inputString, store it in outputString, and return it private String decode() throws InvalidCharacterException{ logger.debug("Decoding"); //Decode every binary number in the string StringBuilder output = new StringBuilder(); for(String baseXString : inputString.split(" ")){ logger.debug("Current number {}", baseXString); //Decode the current binary number int num = Integer.valueOf(baseXString, base); logger.debug("Decoded number {}", num); //Make sure it is in a valid range if((num < 0) && (num > 255)){ throw new InvalidCharacterException("The base" + base + " string '" + baseXString + "' is not a valid character"); } //Convert the int to a char and save it output.append((char)num); } //Save the output logger.debug("Saving output string '{}'", output); outputString = output.toString(); //Return the output return outputString; } //Constructor public BaseX() throws InvalidBaseException{ reset(); setBase(2); } public BaseX(int base) throws InvalidBaseException{ reset(); setBase(base); } //Returns the inputString public String getInputString(){ return inputString; } //Returns the outputString public String getOutputString(){ return outputString; } //Returns the base public int getBase(){ return base; } //Sets the inputString and encodes the message public String encode(String inputString) throws InvalidInputException{ reset(); setInputStringEncode(inputString); return encode(); } public String encode(int base, String inputString) throws InvalidBaseException, InvalidInputException{ reset(); setBase(base); setInputStringEncode(inputString); return encode(); } //Sets the inputString and decodes the message public String decode(String inputString) throws InvalidCharacterException, InvalidInputException{ reset(); setInputStringDecode(inputString); return decode(); } public String decode(int base, String inputString) throws InvalidBaseException, InvalidCharacterException, InvalidInputException{ reset(); setBase(base); setInputStringDecode(inputString); return decode(); } //Makes sure all of the variables are empty public void reset(){ logger.debug("Resetting fields"); inputString = ""; outputString = ""; } }