Hi, I have a school assignment, to send a jpg image,split it into groups of 100 bytes, corrupt it, use a CRC check to locate the errors and re-transmit until it eventually is built back into its original form.
It's practically ready, however when I check out the new images, they appear with errors..
I would really appreciate if someone could look at my code below and maybe locate this logical mistake as I can't understand what the problem is because everything looks ok :S
For the file with all the data needed including photos and error patterns one could download it from this link:http://rapidshare.com/#!download|932tl2|443122762|Data.zip|739
Thanks in advance,
Stefan
p.s dont forget to change the paths in the code for the image and error files
package networks;
import java.io.*; // for file reader
import java.util.zip.CRC32; // CRC32 IEEE (Ethernet)
public class Main {
/**
* Reads a whole file into an array of bytes.
* @param file The file in question.
* @return Array of bytes containing file data.
* @throws IOException Message contains why it failed.
*/
public static byte[] readFileArray(File file) throws IOException {
InputStream is = new FileInputStream(file);
byte[] data=new byte[(int)file.length()];
is.read(data);
is.close();
return data;
}
/**
* Writes (or overwrites if exists) a file with data from an array of bytes.
* @param file The file in question.
* @param data Array of bytes containing the new file data.
* @throws IOException Message contains why it failed.
*/
public static void writeFileArray(File file, byte[] data) throws IOException {
OutputStream os = new FileOutputStream(file,false);
os.write(data);
os.close();
}
/**
* Converts a long value to an array of bytes.
* @param data The target variable.
* @return Byte array conversion of data.
* @see http://www.daniweb.com/code/snippet216874.html
*/
public static byte[] toByta(long data) {
return new byte[] {
(byte)((data >> 56) & 0xff),
(byte)((data >> 48) & 0xff),
(byte)((data >> 40) & 0xff),
(byte)((data >> 32) & 0xff),
(byte)((data >> 24) & 0xff),
(byte)((data >> 16) & 0xff),
(byte)((data >> 8) & 0xff),
(byte)((data >> 0) & 0xff),
};
}
/**
* Converts a an array of bytes to long value.
* @param data The target variable.
* @return Long value conversion of data.
* @see http://www.daniweb.com/code/snippet216874.html
*/
public static long toLong(byte[] data) {
if (data == null || data.length != 8) return 0x0;
return (long)(
// (Below) convert to longs before shift because digits
// are lost with ints beyond the 32-bit limit
(long)(0xff & data[0]) << 56 |
(long)(0xff & data[1]) << 48 |
(long)(0xff & data[2]) << 40 |
(long)(0xff & data[3]) << 32 |
(long)(0xff & data[4]) << 24 |
(long)(0xff & data[5]) << 16 |
(long)(0xff & data[6]) << 8 |
(long)(0xff & data[7]) << 0
);
}
public static byte[] nextNoise(){
byte[] result=new byte[100];
// copy a frame's worth of data (or remaining data if it is less than frame length)
int read=Math.min(err_data.length-err_pstn, 100);
System.arraycopy(err_data, err_pstn, result, 0, read);
// if read data is less than frame length, reset position and add remaining data
if(read<100){
err_pstn=100-read;
System.arraycopy(err_data, 0, result, read, err_pstn);
}else // otherwise, increase position
err_pstn+=100;
// return noise segment
return result;
}
/**
* Given some original data, it is purposefully corrupted according to a
* second data array (which is read from a file). In pseudocode:
* corrupt = original xor corruptor
* @param data The original data.
* @return The new (corrupted) data.
*/
public static byte[] corruptData(byte[] data){
// get the next noise sequence
byte[] noise = nextNoise();
// finally, xor data with noise and return result
for(int i=0; i<100; i++)data[i]^=noise[i];
return data;
}
/**
* Given an array of data, a packet is created. In pseudocode:
* frame = corrupt(data) + crc(data)
* @param data The original frame data.
* @return The resulting frame data.
*/
public static byte[] buildFrame(byte[] data){
// pack = [data]+crc32([data])
byte[] hash = new byte[8];
// calculate crc32 of data and copy it to byte array
CRC32 crc = new CRC32();
crc.update(data);
hash=toByta(crc.getValue());
// create a byte array holding the final packet
byte[] pack = new byte[data.length+hash.length];
// create the corrupted data
byte[] crpt = new byte[data.length];
crpt = corruptData(data);
// copy corrupted data into pack
System.arraycopy(crpt, 0, pack, 0, crpt.length);
// copy hash into pack
System.arraycopy(hash, 0, pack, data.length, hash.length);
// return pack
return pack;
}
/**
* Verifies frame contents.
* @param frame The frame data (data+crc32).
* @return True if frame is valid, false otherwise.
*/
public static boolean verifyFrame(byte[] frame){
// allocate hash and data variables
byte[] hash=new byte[8];
byte[] data=new byte[frame.length-hash.length];
// read frame into hash and data variables
System.arraycopy(frame, frame.length-hash.length, hash, 0, hash.length);
System.arraycopy(frame, 0, data, 0, frame.length-hash.length);
// get crc32 of data
CRC32 crc = new CRC32();
crc.update(data);
// compare crc32 of data with crc32 of frame
return crc.getValue()==toLong(hash);
}
/**
* Transfers a file through a channel in frames and reconstructs it into a new file.
* @param jpg_file File name of target file to transfer.
* @param err_file The channel noise file used to simulate corruption.
* @param out_file The name of the newly-created file.
* @throws IOException
*/
public static void transferFile(String jpg_file, String err_file, String out_file) throws IOException {
// read file data into global variables
jpg_data = readFileArray(new File(jpg_file));
err_data = readFileArray(new File(err_file));
err_pstn = 0;
// variable that will hold the final (transfered) data
byte[] out_data = new byte[jpg_data.length];
// holds the current frame data
byte[] frame_orig = new byte[100];
byte[] frame_sent = new byte[100];
// send file in chunks (frames) of 100 bytes
for(int i=0; i<Math.ceil(jpg_data.length/100); i++){
// copy jpg data into frame and init first-time switch
System.arraycopy(jpg_data, i*100, frame_orig, 0, 100);
boolean not_first=false;
System.out.print("Packet #"+i+": ");
// repeat getting same frame until frame crc matches with frame content
do {
if(not_first)System.out.print("F");
frame_sent=buildFrame(frame_orig);
not_first=true;
}while(!verifyFrame(frame_sent)); // usually, you'd constrain this by time to prevent infinite loops (in
// case the channel is so wacked up it doesn't get a single packet right)
// copy frame to image file
System.out.println("S");
System.arraycopy(frame_sent, 0, out_data, i*100, 100);
}
System.out.println("\nDone.");
writeFileArray(new File(out_file),out_data);
}
// global variables for file data and pointer
public static byte[] jpg_data;
public static byte[] err_data;
public static int err_pstn=0;
public static void main(String[] args) throws IOException {
// list of jpg files
String[] jpg_file={
"C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo1.jpg",
"C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo2.jpg",
"C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo3.jpg",
"C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo4.jpg"
};
// list of error patterns
String[] err_file={
"C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 1.DAT",
"C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 2.DAT",
"C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 3.DAT",
"C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 4.DAT"
};
// loop through all jpg/channel combinations and run tests
for(int x=0; x<jpg_file.length; x++){
for(int y=0; y<err_file.length; y++){
System.out.println("Transfering photo"+(x+1)+".jpg using Pattern "+(y+1)+"...");
transferFile(jpg_file[x],err_file[y],jpg_file[x].replace("photo","CH#"+y+"_photo"));
}
}
}
}