archive file in image

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
That's going to be a hefty piece of memory required to get a copy action done...
How about you read the image byte by byte and immediately write it out to the output file?
Repeat the same for the archive.
Then write with an ObjectOutputStream an integer containing the size of the image file to the output and finally the 4 'fingerprint' characters.

oh actually you're right, gonna need to check that up then
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
Good luck on that, in case you need more info just let me know.
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
Good attempt, but not entirely correct.
Your only mistake (as far as I see) are these lines:
Code:
out.write('\n');
out.write((int) imageFile.length());
This is wrong because: you don't know the size of that integer. If the image is 10,000 bytes, it'll be represented by a 6 character string, but if the image is 100,000 bytes it would be a 7 character string. How do you know where to stop?
An integer on the other is always 4 byte in size (in the memory). It's possible to write an object to an output stream with an ObjectOutputStream. Then reading is done with an ObjectInputStream. If you use this you'll have no problems to determine where the data of the archive ends. The '\n' isn't even required.

I haven't tried it, but I think the following code should roughly be correct:

Code:
(new ObjectOutputStream((OutputStream) out)).write((int) imageFile.length());

A bit longer (more readable):

Code:
outOOS = new ObjectOutputStream((OutputStream) out);
outOOS.write((int) imageFile.length());

Of course I'm assuming there is a constructor ObjectOutputStream(OutputStream arg1), if there isn't the code is wrong.

It's a bit late now, but if you want more info (or more structured) just ask and I'll respond when I have some more time... (and less beer)
 

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
Good attempt, but not entirely correct.
Your only mistake (as far as I see) are these lines:
Code:
out.write('\n');
out.write((int) imageFile.length());
This is wrong because: you don't know the size of that integer. If the image is 10,000 bytes, it'll be represented by a 6 character string, but if the image is 100,000 bytes it would be a 7 character string. How do you know where to stop?
An integer on the other is always 4 byte in size (in the memory). It's possible to write an object to an output stream with an ObjectOutputStream. Then reading is done with an ObjectInputStream. If you use this you'll have no problems to determine where the data of the archive ends. The '\n' isn't even required.

I haven't tried it, but I think the following code should roughly be correct:

Code:
(new ObjectOutputStream((OutputStream) out)).write((int) imageFile.length());
A bit longer (more readable):

Code:
outOOS = new ObjectOutputStream((OutputStream) out);
outOOS.write((int) imageFile.length());
Of course I'm assuming there is a constructor ObjectOutputStream(OutputStream arg1), if there isn't the code is wrong.

It's a bit late now, but if you want more info (or more structured) just ask and I'll respond when I have some more time... (and less beer)

Like http://pastebin.ca/1602112? That destroys the image but the archive works
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
It's probably a bad idea to use two OutputStreams to the same file at the same file. You should finish with the FileOutputStream before making the OOS.

Apart from that it looks good to me. Does this really destroy the image? Adding any other data doesn't destroy it so why would this do? Have you tried a couple of variations yet?

The code:

Code:
InputStream in = null;
InputStream in2 = null;
try {
    in = new FileInputStream(image);
    in2 = new FileInputStream(file);
    OutputStream out = new FileOutputStream(output);
    outOOS = new ObjectOutputStream((OutputStream) out);
    int nextChar;
    int nextChar2;
    while ((nextChar = in.read()) != -1) {
        out.write((char) nextChar);
    }
    while ((nextChar2 = in2.read()) != -1) {
        out.write((char) nextChar2);
    }
    out.flush();
    out.close();
    outOSS = new ObjectOutputStream((OutputStream) new FileOutputStream(output));
    outOOS.write((int) imageFile.length());
    outOOS.write(0x58); // Identify archive
    outOOS.write(0x59); // Identify archive
    outOOS.write(0x12); // Identify archive
    outOOS.write(0xA2); // Identify archive
    outOOS.flush();
} catch (IOException ex) {
	Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} finally {
    try {
        in.close();
        in2.close();
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}
 
Last edited:

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
It's probably a bad idea to use two OutputStreams to the same file at the same file. You should finish with the FileOutputStream before making the OOS.

Apart from that it looks good to me. Does this really destroy the image? Adding any other data doesn't destroy it so why would this do? Have you tried a couple of variations yet?

The code:

Code:
InputStream in = null;
InputStream in2 = null;
try {
    in = new FileInputStream(image);
    in2 = new FileInputStream(file);
    OutputStream out = new FileOutputStream(output);
    outOOS = new ObjectOutputStream((OutputStream) out);
    int nextChar;
    int nextChar2;
    while ((nextChar = in.read()) != -1) {
        out.write((char) nextChar);
    }
    while ((nextChar2 = in2.read()) != -1) {
        out.write((char) nextChar2);
    }
    out.flush();
    out.close();
    outOSS = new ObjectOutputStream((OutputStream) new FileOutputStream(output));
    outOOS.write((int) imageFile.length());
    outOOS.write(0x58); // Identify archive
    outOOS.write(0x59); // Identify archive
    outOOS.write(0x12); // Identify archive
    outOOS.write(0xA2); // Identify archive
    outOOS.flush();
} catch (IOException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} finally {
    try {
        in.close();
        in2.close();
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Yep that breaks it, Should I PM you the dist folder?
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
Yes please.
What kind of image did you use to test? I manually tried it on a png file and the generated image was valid enough to show up in Gnome's image viewer and firefox.
 

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
Yes please.
What kind of image did you use to test? I manually tried it on a png file and the generated image was valid enough to show up in Gnome's image viewer and firefox.

Sent.

Rar file in a png
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
Aha... You noticed how the output file is 11 bytes in size?
I forgot to append x)
Code:
outOSS = new ObjectOutputStream((OutputStream) new FileOutputStream(output, true));
That should prevent the OOS from overwriting the entire file.
 

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
It works now

Reading back in very basic me-code:

File input = new File("input.jpg");
if(input.lastFourBytes() == '\u58' + '\u59' + '\u12' + '\uA2') {
//valid input
int imagesize = input.readInt(input.size()-8 till input.size()-4);
byte[] archive = input.read(imagesize till input.size()-8);
} else {
//invalid input
}


Now at this, this does not work. "Illegal unicode escape" and "Empty character literal"
 
Last edited:

marshian

New Member
Messages
526
Reaction score
9
Points
0
I said it's me-code :p
'\u58' + '\u59' + '\u12' + '\uA2'
should be
((char) 0x58) + ((char) 0x59) + ((char) 0x12) + ((char) 0xA2)
in Java
 

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
I said it's me-code :p
'\u58' + '\u59' + '\u12' + '\uA2'
should be
((char) 0x58) + ((char) 0x59) + ((char) 0x12) + ((char) 0xA2)
in Java


Ooooh I thougt you meant "me code" like in "I code" with a bit of internet slangxD
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
Ooooh I thougt you meant "me code" like in "I code" with a bit of internet slangxD
No it's just pseudo-code used to explain the algorithm. In this case it's easier to write pseudo-code than to explain it all in text :)
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
Beware, non-tested code ahead!

Code:
File input = new File(output);
InputStream inFile = null;
//Initialise the value of 'valid' to false
boolean valid = false;
//This is the signature every file should have
byte[] signature = {0x58, 0x59, 0x12, 0xA2};
try {
    inFile = new FileInputStream(input);
    //Go to the last 4 bytes
    inFile.skip(input.length() - 4);
    //Assume the input file is valid
    valid = true;
   	//Compare each of the last 4 bytes to the expected signature
    for(int i=0; i<4; i++) {
    	if(inFile.read() != filesig[i]) {
    		//In case any of the 4 bytes fails the check, the file is invalid
    		//and the loop is aborted.
    		valid = false;
    		break;
    	}
    }
	//Any exception assumes that the input is invalid.
} catch (FileNotFoundException ex) {
	Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
	valid = false;
} catch (IOException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    valid = false;
}

System.out.println(valid);
 

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
Beware, non-tested code ahead!

Code:
File input = new File(output);
InputStream inFile = null;
//Initialise the value of 'valid' to false
boolean valid = false;
//This is the signature every file should have
byte[] signature = {0x58, 0x59, 0x12, 0xA2};
try {
    inFile = new FileInputStream(input);
    //Go to the last 4 bytes
    inFile.skip(input.length() - 4);
    //Assume the input file is valid
    valid = true;
       //Compare each of the last 4 bytes to the expected signature
    for(int i=0; i<4; i++) {
        if(inFile.read() != filesig[i]) {
            //In case any of the 4 bytes fails the check, the file is invalid
            //and the loop is aborted.
            valid = false;
            break;
        }
    }
    //Any exception assumes that the input is invalid.
} catch (FileNotFoundException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    valid = false;
} catch (IOException ex) {
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    valid = false;
}

System.out.println(valid);

it works! Thanks :D

Btw, try to remember what you call your vars ;). outOOS vs outOSS and filesig vs signature

I had to change the byte[] to int[] tho, otherwise it complained about loss of precision and incompatible types
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
It's not my fault, I was trying to set up some stuff and wanted to post that message in the least amount of time possible while still half focussing on the process...
At least you got the point, that's good enough ;)
 

galaxyAbstractor

Community Advocate
Community Support
Messages
5,508
Reaction score
35
Points
48
Ok I edited the code a bit to check wether or not it's a zip or rar.

Code:
 int a = 0;
                while(a < jFileChooser1.getSelectedFiles().length) {
                   
                    File input = jFileChooser1.getSelectedFiles()[a];
                    InputStream inFile = null;
                    //Initialise the value of 'valid' to false
                    String valid = "false";
                    //This is the signature every file should have
                    int[] filesigrar = {0x58, 0x59, 0x12, 0xA2};
                    int[] filesigzip = {0x58, 0x59, 0x12, 0xA3};
                    try {
                        inFile = new FileInputStream(input);
                        //Go to the last 4 bytes
                        inFile.skip(input.length() - 4);
                        //Assume the input file is valid
                        valid = "true";
                            //Compare each of the last 4 bytes to the expected signature
                        for(int i=0; i<4; i++) {
                            if(inFile.read() == filesigrar[i]) {
                                    //In case any of the 4 bytes fails the check, the file is invalid
                                    //and the loop is aborted.
                                    valid = "RAR";
                                    break;
                            }
                            if(inFile.read() == filesigzip[i]) {
                                    //In case any of the 4 bytes fails the check, the file is invalid
                                    //and the loop is aborted.
                                    valid = "ZIP";
                                    break;
                            }
                            if(inFile.read() != filesigrar[i] || inFile.read() != filesigzip[i] ) {
                                    //In case any of the 4 bytes fails the check, the file is invalid
                                    //and the loop is aborted.
                                    valid = "";
                                    break;
                            }
                        }
                            //Any exception assumes that the input is invalid.
                    } catch (FileNotFoundException ex) {
                        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                        valid = "false";
                    } catch (IOException ex) {
                        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                        valid = "false";
                    }
                    model.addRow(new Object[]{jFileChooser1.getSelectedFiles()[a].getName(),
                    jFileChooser1.getSelectedFiles()[a].length()/1024+" kb", valid});
                    a++;
                }

Thing is... It returns RAR on all files including an archive, even tho I add different sigs now:

Code:
if(archiveType.equals("rar")){
                    outOOS.write(0x58); // Identify archive rar
                    outOOS.write(0x59); // Identify archive rar
                    outOOS.write(0x12); // Identify archive rar
                    outOOS.write(0xA2); // Identify archive rar
                } else if(archiveType.equals("zip")) {
                    outOOS.write(0x58); // Identify archive zip
                    outOOS.write(0x59); // Identify archive zip
                    outOOS.write(0x12); // Identify archive zip
                    outOOS.write(0xA3); // Identify archive zip
                }
(I tested this and it works)
 

marshian

New Member
Messages
526
Reaction score
9
Points
0
*sigh*
You do know what break means, right? :p

Code:
int a = 0;
while(a < jFileChooser1.getSelectedFiles().length) {
	File input = jFileChooser1.getSelectedFiles()[a];
	InputStream inFile = null;
	//Initialise the value of 'valid' to false
	String valid = "false";
	//This is the signature every file should have
	int[] filesigrar = {0x58, 0x59, 0x12, 0xA2};
	int[] filesigzip = {0x58, 0x59, 0x12, 0xA3};
	try {
		inFile = new FileInputStream(input);
		//Go to the last 4 bytes
		inFile.skip(input.length() - 4);
		//Compare each of the last 4 bytes to the expected signatures
		for(int i=0; i<4; i++) {
			if(inFile.read() == filesigrar[i]) {
				valid = "RAR";
			} else if(inFile.read() == filesigzip[i]) {
				valid = "ZIP";
			} else {
				//In case any of the 4 bytes fails the check, the file is invalid
				//and the loop is aborted.
				valid = "false";
				break;
			}
		}
	//Any exception assumes that the input is invalid.
	} catch (FileNotFoundException ex) {
		Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
		valid = "false";
	} catch (IOException ex) {
		Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
		valid = "false";
	}
	model.addRow(new Object[]{jFileChooser1.getSelectedFiles()[a].getName(),
		jFileChooser1.getSelectedFiles()[a].length()/1024+" kb", valid});
	a++;
}
It's not very nice to use a string for "valid" though. You only need 3 values so it would be a better idea to use a short.
 
Top