Created
May 27, 2023 21:36
-
-
Save kylepls/769cfc2f65dce5b973ab547e46cecf3a to your computer and use it in GitHub Desktop.
PsAndQs Encoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.*; | |
import java.nio.charset.StandardCharsets; | |
/** | |
* Encode streams into Ps and Qs. | |
* Why? Because it's mannerly. | |
* P = 0 | |
* Q = 1 | |
*/ | |
public class PsAndQs { | |
public static void main(String[] args) throws IOException { | |
String inputText = "hello world"; | |
System.out.printf("Encoding: %s%n", inputText); | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
PsAndQs.EncoderStream out = new PsAndQs.EncoderStream(baos); | |
out.write(inputText.getBytes(StandardCharsets.UTF_8)); | |
String encoded = baos.toString(); | |
System.out.printf("Encoded Text: %s%n", encoded); | |
PsAndQs.DecoderStream decoderStream = new PsAndQs.DecoderStream(new ByteArrayInputStream(encoded.getBytes(StandardCharsets.UTF_8))); | |
System.out.printf("Decoded: %s%n", new String(decoderStream.readAllBytes())); | |
} | |
private static final byte[] BIT_MASKS = | |
new byte[]{0b1000000, 0b1000000, 0b100000, 0b10000, 0b1000, 0b100, 0b10, 0b1}; | |
public static class EncoderStream extends FilterOutputStream { | |
protected EncoderStream(OutputStream out) { | |
super(out); | |
} | |
@Override | |
public void write(int b) throws IOException { | |
for (byte mask : BIT_MASKS) { | |
if ((b & mask) == mask) { | |
out.write('q'); | |
} else { | |
out.write('p'); | |
} | |
} | |
} | |
} | |
public static class DecoderStream extends FilterInputStream { | |
private boolean eos; | |
private boolean closed; | |
public DecoderStream(InputStream in) { | |
super(in); | |
} | |
@Override | |
public void close() throws IOException { | |
if (!closed) { | |
super.close(); | |
closed = true; | |
eos = true; | |
} | |
} | |
@Override | |
public int read() throws IOException { | |
ensureOpen(); | |
byte read = readByte(); | |
if (eos) { | |
return -1; | |
} else { | |
return read; | |
} | |
} | |
@Override | |
public int read(byte[] b, int off, int len) throws IOException { | |
if (eos) { | |
return -1; | |
} | |
int i = off; | |
int v; | |
while (i < off + len && (v = read()) != -1) { | |
b[i] = (byte) v; | |
i++; | |
} | |
return i - off; | |
} | |
private void ensureOpen() throws IOException { | |
if (closed) { | |
throw new IOException("Stream closed"); | |
} | |
} | |
private byte readByte() throws IOException { | |
byte value = 0; | |
for (int i = 0; i < 8; i++) { | |
int read = in.read(); | |
if (read == 'q') { | |
value |= BIT_MASKS[i]; | |
} else if (read == 'p') { | |
// empty | |
} else if (read == -1) { | |
eos = true; | |
} else { | |
throw new IllegalArgumentException("Invalid character " + read); | |
} | |
} | |
return value; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment