Commit 337b4aba authored by Frédéric Bapst's avatar Frédéric Bapst
Browse files

add s14

parent 96b08d2e
package s14;
import java.io.*;
// Reads any file one bit at a time (most significant bit first)
public class BitReader {
private final FileInputStream fis;
// TODO - A COMPLETER
// private...
public BitReader(String filename) throws IOException {
fis = new FileInputStream(filename);
// TODO - A COMPLETER
}
public void close() throws IOException {
// TODO - A COMPLETER
}
public boolean next() throws IOException {
return false; // TODO - A COMPLETER
}
public boolean isOver() {
return false; // TODO - A COMPLETER
}
//-------------------------------------------
// Tiny demo...
public static void main(String [] args) {
String filename = "a.txt";
try {
BitReader b = new BitReader(filename);
int i=0;
while(!b.isOver()) {
System.out.print(b.next() ? "1" : "0");
i++;
if (i%8 == 0) System.out.print(" ");
if (i%80 == 0) System.out.println("");
}
b.close();
} catch (IOException e) {
throw new RuntimeException("" + e);
}
}
}
package s14;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import org.junit.BeforeClass;
import org.junit.Test;
/** @author alexandr.peclat */
public class BitReaderWriterTestJU {
/** Temporary files names */
private static final String TMP_FOLDER="tmp";
private static final String FILE_WRITE11 = TMP_FOLDER+"/write11";
private static final String FILE_WRITE32 = TMP_FOLDER+"/write32";
private static final String FILE_WRITE27 = TMP_FOLDER+"/write27";
private static final String FILE_READ32 = TMP_FOLDER+"/read32";
/** Tested content, array of 32 bits. */
static final boolean[] CONTENT_BITS_ORIGINAL = new boolean[]{
false, true, true, false, false, true, true, true,
false, true, false, true, true, true, false, true,
true, true, true, true, true, true, false, true,
false, false, true, false, true, true, false, true};
/** Expected content after 32 bits written, without close operation. */
private static final byte[] CONTENT_BYTES_ORIGINAL = new byte[]{0x67, 0x5d, (byte) 0xfd, 0x2d};
/** Expected content after 27 bits written, with close operation (last byte completed by zeros). */
private static final byte[] CONTENT_BYTES_COMPLETED = new byte[]{0x67, 0x5d, (byte) 0xfd, 0x20};
@BeforeClass public static void setUpBeforeClass() throws Exception {
File tempDir = new File(TMP_FOLDER);
tempDir.mkdir();
}
@Test public void testBitWriter32bits() throws IOException {
//Write 32 bits to file
BitWriter writer32 = new BitWriter(FILE_WRITE32);
for(int i=0; i < 32; i++) writer32.put(CONTENT_BITS_ORIGINAL[i]);
writer32.close();
//Read bytes from file and compare with expected results
byte[] bytes = Utils.readBytesFromFile(FILE_WRITE32);
String msg="Wrong number of written bytes.";
assertEquals(msg, CONTENT_BYTES_ORIGINAL.length, bytes.length);
msg="Wrong written byte contents";
assertArrayEquals(msg, CONTENT_BYTES_ORIGINAL, bytes);
}
@Test public void testBitWriter11zeroBits() throws IOException {
//Write 16 bits to file
boolean[] the11ZeroBits = {
false, false, false, false, false, false, false, false,
false, false, false
};
byte[] theTwoZeroBytes = {0,0};
BitWriter writer11 = new BitWriter(FILE_WRITE11);
for (boolean the11ZeroBit : the11ZeroBits) writer11.put(the11ZeroBit);
writer11.close();
//Read bytes from file and compare with expected results
byte[] bytes = Utils.readBytesFromFile(FILE_WRITE11);
String msg="Wrong number of written bytes.";
assertEquals(msg, theTwoZeroBytes.length, bytes.length);
msg="Wrong written byte contents";
assertArrayEquals(msg, theTwoZeroBytes, bytes);
}
@Test public void testBitWriter27bits() throws IOException {
//Write 27 bits to file
BitWriter writer27 = new BitWriter(FILE_WRITE27);
for(int i=0; i < 27; i++)
writer27.put(CONTENT_BITS_ORIGINAL[i]);
writer27.close();
//Read bytes from file and compare with expected results
byte[] bytes = Utils.readBytesFromFile(FILE_WRITE27);
String msg="Wrong number of written bytes.";
assertEquals(msg, CONTENT_BYTES_COMPLETED.length, bytes.length);
msg="Wrong written byte contents";
assertArrayEquals(msg, CONTENT_BYTES_COMPLETED, bytes);
}
/** Test method for {@link BitReader#next()}.
* @throws IOException */
@Test public void testBitReader() throws IOException {
String msg="";
//Write the 4 bytes test content array
Utils.writeBytesToFile(FILE_READ32, CONTENT_BYTES_ORIGINAL);
//Read the file with BitReader
BitReader reader = new BitReader(FILE_READ32);
boolean[] actuals = new boolean[CONTENT_BITS_ORIGINAL.length];
//while(!reader.isOver()){
for(int ir=0; ir<actuals.length; ir++) {
assertFalse(reader.isOver());
assertFalse(reader.isOver() || reader.isOver()); // just to see if isOver() changes the state...
actuals[ir] = reader.next();
}
assertTrue(reader.isOver());
assertTrue(reader.isOver() && reader.isOver());
//Compare read bits with original content
msg="Wrong read sequence";
Utils.assertArrayEquals(msg, CONTENT_BITS_ORIGINAL, actuals);
}
//=====================================================================
/** Some utility methods used by the tests.
* @author alexandr.peclat */
static class Utils{
/**
* Read bytes of a given file.
* @param file Path to the file to read.
* @return Contained data as an array of bytes.
* @throws IOException If the file cannot be found or opened.
*/
public static byte[] readBytesFromFile(String file) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
InputStream is = new FileInputStream(file);
byte[] temp = new byte[1024];
int read;
while((read = is.read(temp)) > 0){
buffer.write(temp, 0, read);
}
is.close();
return buffer.toByteArray();
}
/**
* Write a byte array to a given file.
* @param file Path to the file to write.
* @param bytes Bytes array to write.
* @throws IOException If the file cannot be found or written.
*/
public static void writeBytesToFile(String file, byte[] bytes) throws IOException{
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytes);
fos.close();
}
/**
* Asserts that two arrays of booleans are equals (same content).
* Replace the original method by displaying bit-content in the error message.
* @param message Displayed message if the assertion fails.
* @param expecteds Expected result array.
* @param actuals Actual result array.
*/
public static void assertArrayEquals(String message, boolean[] expecteds, boolean[] actuals){
String msg=message
+ "; expected:<" + toStringBitwise(expecteds, " ")
+ "> but was:<" + toStringBitwise(actuals, " ") + ">";
assertTrue(msg, Arrays.equals(expecteds, actuals));
}
/**
* Convert an array of booleans to a string with bitwise listed content.
* @param bits The array to convert.
* @param bytesSeparator Separator between bytes (each group of 8 bits). Can be empty but not null ("").
* @return String listing the bitwise content of the array.
*/
public static String toStringBitwise(boolean[] bits, String bytesSeparator){
String s = "";
for(int i=0; i < bits.length; i++){
if(i % 8 == 0 && i != 0) s += bytesSeparator;
s += bits[i] ? "1":"0";
}
return s;
}
/**
* Asserts that two arrays of byte are equals (same content).
* Replace the original method by displaying hexadecimal content in the error message.
* @param message Displayed message if the assertion fails.
* @param expecteds Expected result array.
* @param actuals Actual result array.
*/
public static void assertArrayEquals(String message, byte[] expecteds, byte[] actuals){
String msg=message
+ "; expected:<" + toStringHex(expecteds)
+ "> but was:<" + toStringHex(actuals) + ">";
assertTrue(msg, Arrays.equals(expecteds, actuals));
}
/**
* Convert an array of byte to a string with content listed under hexadecimal form.
* @param array The array to convert.
* @return String listing the content of the array in hexadecimal.
*/
public static String toStringHex(byte[] array){
String s = "[";
for(int i=0; i < array.length; i++){
if(i < array.length - 1) s += ", ";
s += String.format("%x", array[i]);
}
return s + "]";
}
}
}
package s14;
import java.io.*;
// Produces a file one bit at a time, (most significant bit first)
// filling the last byte with zeros if necessary
public class BitWriter {
private final FileOutputStream fos;
// TODO - A COMPLETER
// private...
public BitWriter(String filename) throws IOException {
fos = new FileOutputStream(filename);
// TODO - A COMPLETER
}
public void close() throws IOException {
// TODO - A COMPLETER
}
public void put(boolean b) throws IOException {
// TODO - A COMPLETER
}
//-------------------------------------------------------
// Tiny demo...
public static void main(String [] args) {
String filename = "a.txt";
String bytes = "01000001 01000010 010001";
// A B D (01000100)
try {
BitWriter b = new BitWriter(filename);
for(int i=0; i<bytes.length(); i++) {
if (bytes.charAt(i) == '1') b.put(true);
if (bytes.charAt(i) == '0') b.put(false);
}
b.close();
} catch (IOException e) {
throw new RuntimeException("" + e);
}
}
}
package s14;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
//======================================================================
public class LempelZiv {
//======================================================================
static class LzvCodeTable {
private ArrayList<byte[]> table;
public LzvCodeTable() {
table = new ArrayList<>();
table.add(new byte[0]); // dummy "empty string" entry
}
private int lookup(byte[] s) {
for (int i=0; i<table.size(); i++)
if (Arrays.equals(s, table.get(i))) return i;
return -1;
}
public int size() { return table.size(); }
public boolean contains(byte[] s) {
if (s.length==0) return true;
return (lookup(s) != -1);
}
public int putAndCode(byte[] s, byte c) {
int i = lookup(s);
byte[] z=addToByteArray(s, c);
table.add(z);
return i;
}
public byte[] putAndDecode(int index, byte c) {
byte[] s = table.get(index);
byte[] z=addToByteArray(s, c);
table.add(z);
return z;
}
public String toString() {
String s = "";
for (int i=0; i<table.size(); i++) {
byte[] b = table.get(i);
String w = "";
for(byte c:b) w+=Character.isLetterOrDigit((char)c) ? (char)c : "-";
s += "" + i + ": " + Arrays.toString(b) + " \"" + w + "\"\n";
}
return s;
}
}
//======================================================================
static class LzvItem {
final int entryNb;
final byte appendedChar;
public LzvItem(int entryNb, byte appendedChar) {
this.entryNb = entryNb;
this.appendedChar = appendedChar;
}
@Override public boolean equals(Object o) {
if (o == null || this.getClass() != o.getClass()) return false;
LzvItem oo = (LzvItem)o;
return oo.entryNb==entryNb && oo.appendedChar==appendedChar;
}
}
//======================================================================
public static void code(String infile, String outfile) throws IOException {
FileInputStream bis = new FileInputStream(infile);
FileOutputStream bos = new FileOutputStream(outfile);
PrintWriter tos = new PrintWriter(new FileWriter(outfile+".txt"));
LzvCodeTable t = new LzvCodeTable();
int crt = bis.read();
byte [] prefix=new byte[0];
while(crt != -1) {
byte crtByte = (byte)crt;
// TODO - A COMPLETER
// ...
// ... LzvItem item = new LzvItem(...
// ... printItem(bos, tos, item);
// ...
// Remember there are two cases where EOF can happen:
// - just after a fresh item;
// - with a current word that forms a known prefix; in this case
// we will add again this word in the code table.
}
bis.close();
bos.close();
tos.close();
System.out.println("Code table: size = "+t.size());
if (t.size() < 10) {
System.out.println("Table Content:");
System.out.println(t);
}
}
public static void decode(String infile, String outfile) throws IOException {
FileInputStream bis = new FileInputStream(infile);
Scanner tis = new Scanner(new FileReader(infile+".txt"));
FileOutputStream bos = new FileOutputStream(outfile);
LzvCodeTable t = new LzvCodeTable();
LzvItem item = readItem(bis, tis);
while(item != null) {
byte[] s = t.putAndDecode(item.entryNb, item.appendedChar);
bos.write(s);
item=readItem(bis, tis);
}
bis.close();
tis.close();
bos.close();
System.out.println("Code table: size = "+t.size());
if (t.size() < 10) {
System.out.println("Table Content:");
System.out.println(t);
}
}
private static byte[] addToByteArray(byte [] t, byte b) {
byte [] res=new byte[t.length+1];
System.arraycopy(t, 0, res, 0, t.length);
res[res.length-1] = b;
return res;
}
private static void printItem(FileOutputStream bos,
PrintWriter tos,
LzvItem item) throws IOException {
printItemAsBinary(bos, item); // really compressed!
printItemAsText (tos, item); // useful for debugging
}
private static void printItemAsBinary(FileOutputStream bos, LzvItem item) throws IOException {
// TODO - A COMPLETER
}
private static void printItemAsText( PrintWriter tos, LzvItem item) throws IOException {
tos.print(" "+item.entryNb);
tos.print(" "+item.appendedChar);
char c = (char) item.appendedChar;
if (Character.isLetterOrDigit(c))
tos.print(" \"" + c + "\"");
else
tos.print(" " + "-");
tos.println();
}
private static LzvItem readItem(FileInputStream bis, Scanner tis) throws IOException {
LzvItem res = readItemFromBinary(bis);
LzvItem res1 = readItemFromText (tis);
if (res==null && res1==null) return res;
if((res==null ^ res1==null) || !res1.equals(res)) {
System.out.println("Oups... binary and text formats don't agree!");
System.exit(-1);
}
return res;
}
/** returns null when there is no item (EOF) */
private static LzvItem readItemFromBinary(FileInputStream bis) throws IOException {
return null; // TODO - A COMPLETER
}
private static LzvItem readItemFromText(Scanner tis) throws IOException {
if (!tis.hasNext()) return null;
int code = tis.nextInt();
byte crtByte = tis.nextByte();
tis.next(); // dummy character
LzvItem res = new LzvItem(code, crtByte);
return res;
}
// ------------------------------------------------------------
// ------------------------------------------------------------
// ------------------------------------------------------------
public static void main(String [] args) {
if (args.length != 3 ) usage();
String cmd = args[0];
try {
if (cmd.equals("code"))
code(args[1], args[2]);
else if (cmd.equals("decode"))
decode(args[1], args[2]);
else
usage();
} catch (IOException e) {
System.err.println(e);
e.printStackTrace();
}
}
// ------------------------------------------------------------
private static void usage() {
System.out.println("Usage: LempelZiv code infile outfile");
System.out.println(" or: LempelZiv decode infile outfile");
System.exit(-1);
}
}
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment